在将我的android项目从java翻译成Kotlin时,我遇到了Kotlin的一些问题。 假设我有接口I和接口O,它扩展了接口I.
interface I{
}
interface O: I{
}
泛型类A,它具有扩展interfaceI的泛型参数V,以及扩展了类A的泛型类B:
abstract class A<V: I> {
}
class B : A<O>() {
}
当我试图创造这样的财产时:
val returnB: A<I>
get() = b
我收到编译错误&#39;要求A,找到B&#39;。在Java中,这将没有任何问题。我如何使用Kotlin访问它?
我需要在我的应用程序中对Basic类使用这种方法。
BaseViewModel,它具有Navigator类的通用参数:
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,但编译器抛出错误&#39;必需的BaseViewModel&#39;。
And i tried to change
override val viewModel: BaseViewModel<BaseNavigator>
get() = mViewModel
to
override val viewModel: AuthViewModel
get() = mViewModel
但是在这种情况下编译器抛出错误&#39;属性类型是&#39; AuthViewModel&#39;,这不是被覆盖的子类型&#39;。
更新 当我向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
}
答案 0 :(得分:2)
看起来你期望type参数表现为 covariantly 。 Kotlin使用声明站点方差。如果未指定方差,则泛型类型参数为不变。
换句话说,目前A<I>
和A<O>
之间没有任何关系。但是如果你宣布
abstract class A<out V : I>
然后A<O>
是A<I>
的子类型。
(还有<in>
用于反演,反过来也是如此。有关详细信息,请参阅https://kotlinlang.org/docs/reference/generics.html。)