列表回调参数上的 Kotlin 通配符捕获
Kotlin Wildcard Capture on List Callback Parameter
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 方法中扩展模型,覆盖与 Kotlin 中的接口不匹配。有了它,我得到以下错误:
doSomething(<java.util.List<com.yada.Model>) cannot be applied to (java.util.List<capture<? extends com.yada.Model>>)
为什么需要通配符捕获,为什么不允许它用于非通配符方法?
问题源于 Kotlin 集合 variant,并且 Java 仅具有通过通配符实现的使用位置差异(捕获与通配符有关,但不完全是 ? extends ...
语法本身)。
在 Kotlin 中我们说 List<Model>
表示 "read-only list of Model
or subtypes of Model
",当我们在 Java 中表示相同时表示 "mutable list of exactly Model
and nothing else"。大致意思是 Kotlin 的 List<Model>
的意思,在 Java 中我们必须说 List<? extends Model>
,这就是为什么要使覆盖起作用,您必须将通配符添加到 Java 代码中.
现在,你的 doSomething
写成 Java 并且说它想要 "a list of exactly Model
",当你给它 "a list of Model
or its subtypes" 时, Java编译器抱怨,因为它可能很危险:doSomething
可能会尝试做一些不合法的事情,例如 ModelImpl
,因为它认为它正在处理 Model
的列表.
截至目前(Kotlin Beat 2),您有两个选择:
- 在您的 Kotlin 代码中使用
MutableList<Model>
- 这正是 Java 的 List<Model>
或 的意思
- 定义
doSomething
以便它需要 List<? extends Model>
,这就是您当前的 Kotlin 代码的含义。
在 Kotlin 的下一次更新中,我们将在类型上添加一个注释,以便更清晰地解决此问题。
解决捕获问题
你可以这样做:
void doSomething(List<Model> models) {
new ArrayList(models)
}
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 方法中扩展模型,覆盖与 Kotlin 中的接口不匹配。有了它,我得到以下错误:
doSomething(<java.util.List<com.yada.Model>) cannot be applied to (java.util.List<capture<? extends com.yada.Model>>)
为什么需要通配符捕获,为什么不允许它用于非通配符方法?
问题源于 Kotlin 集合 variant,并且 Java 仅具有通过通配符实现的使用位置差异(捕获与通配符有关,但不完全是 ? extends ...
语法本身)。
在 Kotlin 中我们说 List<Model>
表示 "read-only list of Model
or subtypes of Model
",当我们在 Java 中表示相同时表示 "mutable list of exactly Model
and nothing else"。大致意思是 Kotlin 的 List<Model>
的意思,在 Java 中我们必须说 List<? extends Model>
,这就是为什么要使覆盖起作用,您必须将通配符添加到 Java 代码中.
现在,你的 doSomething
写成 Java 并且说它想要 "a list of exactly Model
",当你给它 "a list of Model
or its subtypes" 时, Java编译器抱怨,因为它可能很危险:doSomething
可能会尝试做一些不合法的事情,例如 ModelImpl
,因为它认为它正在处理 Model
的列表.
截至目前(Kotlin Beat 2),您有两个选择:
- 在您的 Kotlin 代码中使用
MutableList<Model>
- 这正是 Java 的List<Model>
或 的意思
- 定义
doSomething
以便它需要List<? extends Model>
,这就是您当前的 Kotlin 代码的含义。
在 Kotlin 的下一次更新中,我们将在类型上添加一个注释,以便更清晰地解决此问题。
解决捕获问题
你可以这样做:
void doSomething(List<Model> models) {
new ArrayList(models)
}