3

为什么会在 Kotlin 中发生这种情况:

val list: List<Int> = listOf(1, 2, 3)// Immutable list

if(list is MutableCollection<*>){// why this "if" condition is true?
    println("is mutable")// this line is printed
    (list as MutableCollection<Int>).add(4) // this results to java.lang.UnsupportedOperationException
}

list is MutableCollection返回 true 表示 Kotlin 不可变集合对象实现MutableCollection了接口,但它不会更改集合中的项目,而是抛出UnsupportedOperationException

这是真的吗?如果是,为什么不可变集合对象MutableCollection在 Kotlin 中实现接口?

是不是因为 Kotlin 集合继承自 Java 集合和更改方法(添加、删除、...)已经存在,避免更改集合的唯一方法是覆盖它并抛出异常(即使这是真的,它不是Kotlin 不可变集合对象实现MutableCollection接口所必需的,因为 java 更改集合方法已经存在并且可以被覆盖)?

4

1 回答 1

5

不,这不是正确的解释。此代码应该可以帮助您了解发生了什么:

val list: List<Int> = listOf(1, 2, 3) 

println("list class is = ${list::class.java}")

if(list is MutableCollection<*>) {
    println("is mutable") 
    (list as MutableList<Int>)[0] = 42
    println(list)
}

输出是

list class is = class java.util.Arrays$ArrayList
is mutable
[42, 2, 3]

因此,解释是listOf(1, 2, 3)返回一个 Arrays$ArrayList 列表,即在 Java 中通过执行Arrays.asList(1, 2, 3). 它是一个可变列表,但您不能向其中添加任何内容,因为它具有固定大小,因为它由数组支持。

Kotlin 列表并不是真正不可变的。它们只是没有任何方法可以改变它们:它们只是不可变接口,只公开实际可变列表的只读方法。如果您作弊并将列表转换为可变列表,那么,如果该列表实际上是 Java 列表,则转换将成功,但您不知道您是否真的能够改变它们,就像在 Java 中一样: List 可以是一个空列表,它根本不能被改变,也可以是一个不可调整大小的列表,如上面的例子,或者一个完全可变的列表,如 ArrayList。

于 2018-12-27T22:43:33.987 回答