Mar*_*dik 6 java collections interop kotlin
我很惊讶地看到这个程序甚至可以编译,但结果更让我惊讶:
import java.util.Collections.swap
fun main(args: Array<String>)
{
val immutableList = List(2) { it } // contents are [0, 1]
swap(immutableList, 0, 1)
println(immutableList) // prints [1, 0]
}
Run Code Online (Sandbox Code Playgroud)
该swap函数在库中实现为:
public static void swap(List<?> list, int i, int j) {
list.set(i, list.set(j, list.get(i)));
}
Run Code Online (Sandbox Code Playgroud)
其中List是可变的 Java 列表,而不是不可变的 Kotlin 列表。所以我认为其他 Java 函数也能工作。例如:
reverse(immutableList)
Run Code Online (Sandbox Code Playgroud)
工作,但其他人,如fill函数,甚至不编译:
fill(immutableList, 3)
Run Code Online (Sandbox Code Playgroud)
产生以下错误消息:
类型推断失败:fun fill(p0: MutableList!, p1: T!): Unit cannot be applied to (List,Int) Type mismatch: inferred type is List but MutableList! 预料之中
然而List,fill函数的参数具有不同的类型界限reverse:
public static <T> void fill(List<? super T> list, T obj)
public static void reverse(List<?> list)
Run Code Online (Sandbox Code Playgroud)
所以似乎没有类型界限,Java 函数可以为所欲为。
有人可以解释这怎么可能吗?这是设计使然,还是只是互操作的限制?
无法编译的函数与 kotlin 无关,而是与 java 如何处理协变和逆变集合有关。
\n\n\n\n\n\n\n不能将任何内容放入使用 extends\n 通配符\xe2\x80\x94 声明的类型中,除了值 null,该值属于每个引用\n 类型
\n
例如,如果您有以下代码。
\n\nList<? extends Number> numbers = new ArrayList<Integer>();\nRun Code Online (Sandbox Code Playgroud)\n\n然后你可以这样做
\n\n numbers.add(null);\nRun Code Online (Sandbox Code Playgroud)\n\n但如果您尝试执行以下任一操作
\n\nnumbers.set(0, Integer.valueOf(10)); // case 1\nnumbers.set(1, numbers.get(0)); // case 2\nRun Code Online (Sandbox Code Playgroud)\n\n在情况 1中,编译器不会让您这样做,因为编译器无法知道列表的确切类型,在这种情况下,它是一个整数列表,在其他情况下,它可能会根据某些运行时分配一个双精度列表健康)状况。
\n\n在情况 2中,编译器无法确认插入列表中的对象的类型,并产生错误。您可以使用Wildcard Capture解决案例 2 中的问题。
\n\n其次是关于在 java 方法中改变 kotlin 列表的问题。
\n\n我们必须了解 kotlin 集合类与旧的 java 集合类相同,并且 kotlin 没有自己的集合实现。kotlin 所做的是将 java 集合接口分为可变接口和只读接口。\n如果你在 kotlin 中创建一个数组列表,然后检查它的类,你将得到相同的 java.util.ArrayList
\n\n现在,鉴于 java 不像 kotlin 那样有任何可变列表和只读列表的概念,因此无法阻止 java 方法改变只读 kotlin 列表。因为对于java代码来说这只是一个列表实现。
\n\n以下是《Kotlin in Action》一书中的相关文本
\n\n\n\n当您需要调用 Java 方法并将集合作为\n 参数传递时,您可以直接执行此操作,无需任何额外的步骤。例如,如果您有一个采用 java.util.Collection 作为参数的 Java 方法,则可以将任何 Collection 或 Mutable Collection 值作为参数传递给该参数。
\n\n这对于集合的可变性有重要的影响。由于 Java 不区分只读集合和可变集合,因此即使集合在 Kotlin 端声明为只读集合,Java 代码也可以修改该集合。Kotlin 编译器无法完全分析 Java 代码中对集合执行的操作,因此Kotlin 无法拒绝 a n 调用将只读 Collection 传递给修改它的 Java 代码。
\n
| 归档时间: |
|
| 查看次数: |
376 次 |
| 最近记录: |