列表回调参数的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) { } } 

科特林:

 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方法中扩展了Model,覆盖与Kotlin中的接口不匹配。 有了它,我得到以下错误:

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

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

这个问题源于Kotlin集合是变体 ,而Java只有通过通配符实现的use-site 变体 (捕获是连接到通配符的东西,但不完全是? extends ...语法本身)。

当在Kotlin中我们说List<Model>意味着“ Model或子类型的只读列表”,当我们在Java中说相同的时候,它意味着“完全Model可变列表,而没有其他”。 大致意思是Kotlin的List<Model>含义,在Java中我们不得不说List<? extends Model> 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> List<? extends Model> ,这就是你现在的Kotlin代码的含义。

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