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

6

Java:

public class JavaClass implements ModelController.Callback {

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

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

}

Kotlin:

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

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

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

interface Model {

}

在Java的onModelsLoaded方法中,如果没有使用? extends Model,那么重载方法与Kotlin接口不匹配。但是如果使用它,将会得到以下错误:

doSomething(<java.util.List<com.yada.Model>) cannot be applied to (java.util.List<capture<? extends com.yada.Model>>)

为什么需要通配符捕获,为什么不能在非通配符方法中使用它?
2个回答

17
该问题源于Kotlin集合具有变体,而Java只有使用点位变体,这是通过通配符实现的(捕获与通配符相关,但不完全是? extends ...语法本身)。
当我们在Kotlin中说List<Model>时,意味着“只读的Model列表或Model的子类型”,而当我们在Java中说同样的话时,意味着“可变的Model列表,仅限于Model而已”。为了大致表示Kotlin的List<Model>的含义,在Java中我们必须说List<? extends Model>,这就是为什么要在Java代码中添加通配符才能使覆盖工作。
现在,你的doSomething写成Java,并且要求“恰好是Model的列表”,当你给它“Model或其子类型的列表”时,Java编译器会抱怨,因为这可能很危险:doSomething可能会尝试做一些对于例如ModelImpl的列表不合法的事情,因为它认为自己正在处理Model的列表。

目前(Kotlin Beat 2),您有两个选择:

  • 在您的Kotlin代码中使用MutableList<Model>——这意味着与Java的List<Model>完全相同;或者
  • 定义doSomething,使其接受List<? extends Model>,这是您当前Kotlin代码的含义。

在Kotlin的下一个更新中,我们将为类型添加注释,以便更清晰地解决此问题。


0
为解决关于capture<? extends Model>的问题,您可以尝试以下做法:
void doSomething(List<Model> models) {
    new ArrayList(models)
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接