请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

关于Kotlin的协变问题

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 泛型

0 回复 有任何疑惑可以回复我~
  • 提问者 爱吃Toast #1
    多谢老师解答!
    回复 有任何疑惑可以回复我~ 2017-09-21 22:53:27
问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信