Kotlin通用属性问题

在将我的Android项目从Java转换为Kotlin时,我遇到了Kotlin的一些问题。 假设我有接口I和扩展接口I的接口O.

interface I{ } interface O: I{ } 

通用类A具有扩展接口I的通用参数V,扩展类A的通用类B:

 abstract class A<V: I> { } class B : A<O>() { } 

当我试图创建这样的属性:

 val returnB: A<I> get() = b 

我得到编译器错误“需要A,找到B”。 在Java中,这将工作没有任何问题。 我怎样才能使用Kotlin访问?

我需要在我的应用程序中使用这种方法的基本类。

具有Navigator类的泛型参数的BaseViewModel:

 abstract class BaseViewModel<N>(application: Application, val repositoryProvider: RepositoryProvider) : AndroidViewModel(application) { var navigator: N? = null fun onDestroyView() { navigator = null } open fun onViewAttached() { } } 

BaseActivity类:

 abstract class BaseActivity<T : ViewDataBinding, V : BaseViewModel<BaseNavigator>> : AppCompatActivity(), BaseFragment.Callback, BaseNavigator { // ....... private var mViewModel: V? = null /** * Override for set view model * @return view model instance */ abstract val viewModel: V // ....... } 

BaseNavigator接口用于VM – 查看通信:

 interface BaseNavigator { fun invokeIntent(intent: Intent?, b: Bundle?, c: Class<*>?, forResult: Boolean, requestCode: Int) fun replaceFragment(fragment: Fragment, addToBackStack: Boolean) fun showDialogFragment(fragment: DialogFragment?, tag: String?) fun showToast(message: String?) } 

这里我扩展这些类的示例代码:

AuthViewModel:

 class AuthViewModel(context: Application, repositoryProvider: RepositoryProvider) : BaseViewModel<AuthNavigator>(context,repositoryProvider) { // .... } 

AuthNavigator:

 interface AuthNavigator : BaseNavigator { fun requestGoogleAuth(code: Int) fun requestFacebookAuth(callback: FacebookCallback<LoginResult>) } 

和出现错误的AuthActivity类:

 class AuthActivity : BaseActivity<ActivityAuthBinding, BaseViewModel<BaseNavagator>>(), GoogleApiClient.OnConnectionFailedListener, AuthNavigator { @Inject lateinit var mViewModel: AuthViewModel override val viewModel: BaseViewModel<BaseNavigator> get() = mViewModel // Required:BaseViewModel<BaseNavigator> Found: AuthViewModel 

}

我也尝试将AuthActivity中的泛型参数从BaseViewModel更改为AuthViewModel,但是编译器会抛出错误“必需的BaseViewModel”。

 And i tried to change override val viewModel: BaseViewModel<BaseNavigator> get() = mViewModel to override val viewModel: AuthViewModel get() = mViewModel 

但在这种情况下,编译器会抛出错误'属性类型是'AuthViewModel',这不是重写的子类型。

更新:当我添加属性到BaseViewModel时,工作:

 BaseViewModel<out N : BaseNavigator> 

但在这种情况下,我只能创建

 private var navigator: N? = null 

我需要公开,所以我可以在Activity类中进行设置。 我可以创建这个属性的公共setter? 当我试图创建setter发生错误:

 private var navigator: N? = null fun setNavigator(n: N) { // error: Type parameter N is declared as 'out' but occurs in 'in' position in type N navigator = n } 

它看起来像你期待的类型参数协同行为。 Kotlin使用声明站点差异。 如果不指定方差,泛型类型参数是不变的

换句话说,现在A<I>A<O>之间没有关系。 但是,如果你声明

 abstract class A<out V : I> 

那么A<O>A<I>一个子类型。

(还有<in>是反转的,反过来也是如此,更多细节见https://kotlinlang.org/docs/reference/generics.html