Несоответствие типа Котлина

У меня есть вопрос об общих типах, подтипах и несоответствии между ними. У меня есть конкретные классы структуры и интерфейса. Я покажу вам и, пожалуйста, объясните мне, почему происходит несоответствие типов.

Допустим, я готовлю свой 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, и продолжить изучение этого вопроса.

Другие вопросы по тегам