列表回调参数的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的下一次更新中,我们将在类型上添加一个注释,以便为这个问题提供一个更简洁的解决方法。