列表回调参数上的Kotlin通配符捕获

Jer*_*man 3 kotlin

Java的:

public class JavaClass implements ModelController.Callback {

    @Override
    public void onModelsLoaded(@NonNull List<? extends Model> models) {
        doSomething(models);
    }

    private void doSomething(List<Model> models) { }

}
Run Code Online (Sandbox Code Playgroud)

科特林:

class ModelController {
    var callback = WeakReference<Callback>(null)

    interface Callback {
        fun onModelsLoaded(models: List<Model>)
    }

    fun someFunction() {
        callback.get().onModelsLoaded(ArrayList<Model>())
    }
}

interface Model {

}
Run Code Online (Sandbox Code Playgroud)

没有?在Java onModelsLoaded方法中扩展Model,覆盖与Kotlin中的接口不匹配.有了它,我收到以下错误:

doSomething(<java.util.List<com.yada.Model>) cannot be applied to (java.util.List<capture<? extends com.yada.Model>>)
Run Code Online (Sandbox Code Playgroud)

为什么需要通配符捕获,为什么不允许它用于非通配符方法?

And*_*lav 8

问题源于Kotlin集合的变体,Java只有通过通配符实现的使用站点差异(捕获是与通配符相关但不完全是? extends ...语法本身).

当我们在Kotlin中说它List<Model>意味着"只读列表Model或子类型Model"时,当我们在Java中说同样的词时,它意味着"确切Model而无其他的可变列表".大致意味着Kotlin的List<Model>意思,在Java中我们不得不说List<? extends Model>,这就是为什么要使覆盖工作,你必须将通配符添加到Java代码中.

现在,你doSomething用Java编写并说它想要"精确列表Model",当你给它"一个Model或它的子类型列表"时,Java编译器会抱怨,因为它可能很危险:doSomething可能会尝试做某事例如,这对于列表来说是不合法的ModelImpl,因为它认为它正在列表中Model.

截至目前(Kotlin Beat 2),您有两种选择:

  • 使用MutableList<Model>在科特林代码-这意味着正是Java的List<Model>手段,或
  • 定义doSomething所需List<? extends Model>,这是您当前的Kotlin代码所意味着的.

在Kotlin的下一次更新中,我们将在类型上添加注释,以便为此问题提供更简洁的解决方法.