关于Kotlin的协变问题
来源:10-1 基本互操作

爱吃Toast
2017-09-21
Benny老师,我在构造方法里传入RecyclerView.Adapter类型的参数,如果是Java,参数定义为RecyclerView.Adapter即可,而Kotlin没有Raw类型,参数定义为RecyclerView.Adapter<*>或RecyclerView.Adapter<out RecyclerView.ViewHolder>,在调用实参的onBindViewHolder(...)方法会报错:
Out-projected type 'RecyclerView.Adapter<out RecyclerView.ViewHolder>' prohibits the use of 'public abstract fun onBindViewHolder(p0: VH!, p1: Int): Unit defined in android.support.v7.widget.RecyclerView.Adapter'
代码情况如下:
class HeaderAndFooterWrapper(private val innerAdapter: RecyclerView.Adapter<*>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() { override fun onBindViewHolder(holder: RecyclerView.ViewHolder, pos: Int) { if (isHeaderViewPos(pos)) return if (isFooterViewPos(pos)) return innerAdapter.onBindViewHolder(holder, pos - headersCount) } }
如何解决innerAdapter.onBindViewHolder报错问题呢?
写回答
1回答
-
是这样的哈,首先你必须明白一点,协变的类型是不允许当做参数传入的,因为这样会引发不安全的情况发生,所以才会报这个错误。仔细体会一下为什么协变是 out,因为只出不进呀。
逆变的情况也类似,就是只进不出。
为什么会出现这样的情况?
class SomeViewHolder(...): RecyclerView.ViewHolder(...){ ... } //协变,用父类引用指向子类 val adapter: RecyclerView.Adapter<RecyclerView.ViewHolder> = RecyclerView.Adapter<SomeViewHolder>(...) //跪了,因为 adapter 需要的实际上是 SomeViewHolder 的实例,而不是父类的实例 adapter.onBindViewHolder(RecyclerView.ViewHolder(), 0)
实际上你这个例子并不需要协变,你看我下面的写法:
class HeaderAndFooterWrapper<T : RecyclerView.ViewHolder>(private val innerAdapter: RecyclerView.Adapter<T>) : RecyclerView.Adapter<T>() { override fun onBindViewHolder(holder: T, position: Int) { throw NotImplementedError() } override fun getItemCount() : Int{ throw NotImplementedError() } override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): T { throw NotImplementedError() } }
如果你对协变需要有进一步了解,看我之前的这篇文章:Kotlin 泛型
012017-09-21
相似问题