Несоответствие типа Котлина
У меня есть вопрос об общих типах, подтипах и несоответствии между ними. У меня есть конкретные классы структуры и интерфейса. Я покажу вам и, пожалуйста, объясните мне, почему происходит несоответствие типов.
Допустим, я готовлю свой MVP-фреймворк и у меня есть следующие интерфейсы и классы:
Это высшая абстракция
interface Presenter<in V : AbstractView> {
fun attachView(view: V)
fun detachView()
fun onDestory() {
}
}
Абстрактный класс содержит конкретные методы и реализацию Presenter.
abstract class AbstractPresenter<V : AbstractView> : Presenter<V>, LifecycleObserver {
private var viewReference: WeakReference<V?>? = null
protected abstract fun onAttached(view: V)
final override fun attachView(view: V) {
viewReference = WeakReference(view)
onAttached(view)
}
final override fun detachView() {
viewReference?.clear()
viewReference = null
onDetached()
}
protected open fun onDetached() {
}
}
контракт
interface DashboardContract {
interface View : AbstractView {
}
abstract class Presenter : AbstractPresenter<View>(){
}
}
и наконец
class DashboardPresenter : DashboardContract.Presenter() {
override fun onAttached(view: DashboardContract.View) {
}
}
С точки зрения AbstractView
это выглядит проще. Есть просто интерфейс AbstractView
, В контракте DashboardContract.View
продолжается AbstractView
интерфейс и мой DashboardActivity
реализовать это DashboardContract.View
интерфейс.
class DashboardActivity : BaseActivity(), DashboardContract.View { ... }
Поэтому, когда я создаю DashboardPresenter
как собственность в моем DashboardActivity
и создать метод fun getPresenter() : Presenter<AbstractView>
тогда я получил Type mismatch error
Зачем? не подтип Presenter<AbstractView>
?
fun getPresenter() : AbstractPresenter<AbstractView> {
return dashboardPresenter // The type is DashboardPresenter
}
Давайте посмотрим на код Java:
Я смотрю код Java от декомпиляции Kotlin. Я поставил это ниже. Вот как Presenter
похоже:
public interface Presenter {
void attachView(@NotNull AbstractView var1);
void detachView();
void onDestory();
@Metadata(...)
public static final class DefaultImpls {
public static void onDestory(Presenter $this) {
}
}
}
Я думал, что если я использую универсальный класс в Kotlin, я получаю универсальный класс также в Java. Я был неправ.
AbstractPresenter
дает:
public abstract class AbstractPresenter implements Presenter, LifecycleObserver {
private WeakReference viewReference;
protected abstract void onAttached(@NotNull AbstractView var1);
public final void attachView(@NotNull AbstractView view) {
Intrinsics.checkParameterIsNotNull(view, "view");
this.viewReference = new WeakReference(view);
this.onAttached(view);
}
public final void detachView() {
WeakReference var10000 = this.viewReference;
if(this.viewReference != null) {
var10000.clear();
}
this.viewReference = (WeakReference)null;
this.onDetached();
}
protected void onDetached() {
}
public void onDestory() {
DefaultImpls.onDestory(this);
}
}
контракт
public interface DashboardContract {
@Metadata(...)
public interface View extends AbstractView {
}
@Metadata(...)
public abstract static class Presenter extends AbstractPresenter {
}
}
DashboardPresetner
:
public final class DashboardPresenter extends Presenter {
protected void onAttached(@NotNull View view) {
Intrinsics.checkParameterIsNotNull(view, "view");
}
// $FF: synthetic method
// $FF: bridge method
public void onAttached(AbstractView var1) {
this.onAttached((View)var1);
}
}
1 ответ
Вы должны изменить родителя Presenter
в DashboardContract
использовать AbstractView
вместо View
:
abstract class Presenter : AbstractPresenter<AbstractView>()
Я не уверен, почему вы не можете использовать View
вместо этого это может быть недостатком в рекурсивной проверке типов Kotlin. Возможно, было бы интересно посмотреть, что представляет собой соответствующий код Java, и продолжить изучение этого вопроса.