val list = listOf(1, 2, 3)
fun main() {
if (list is MutableList) {
list.add(4)
}
}上面的代码引发下面的运行时异常。
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.AbstractList.add (:-1)
at java.util.AbstractList.add (:-1)
at FileKt.main (File.kt:5) 在阅读了Kotlin的收藏文件之后,我了解到kotlin通过接口区分可变集合和不可变集合,并且不变接口没有任何像add()这样的可变方法,但是我想知道在JVM平台上List和MutableList的底层实现是什么?在这种情况下,它看起来像底层的具体类有add()方法,但是它会抛出一个异常。
问题:
由于我在Java方面经验不多,所以很难在JVM中找到List和MutableList接口的具体实现。如果有人向我指出代码或跟踪这些接口下的实际java集合的方法,那就太好了。这两个接口是由相同的java集合还是由不同的java集合实现的?
注:
我这样做是为了学习,我知道这是非常糟糕的代码,我应该使用.toMutableList()扩展函数,而不是智能转换。
发布于 2022-08-30 20:57:49
正如您所说的,Java并不区分可变列表和不可变列表。kotlin.List (或者至少在类型系统中不区分。) ,因此将java.util.List和kotlin.MutableList类型都映射到java.util.List接口。
这样做的不幸后果是支票:
if (list is MutableList)…实际上,它只是检查对象是否是java.util.List,所以可变列表和不可变列表都将通过测试。
这就是为什么您的代码要抛出一个UnsupportedOperationException (这是区分不可变列表和任何其他可选特性的一种方法)。
我不知道有什么方法可以可靠地区分可变列表和不可变列表,除非尝试修改它们并查看它们是否抛出异常…
同样值得注意的是,listOf()并不承诺返回任何特定的实现。 所能告诉你的就是它会返回一些实现kotlin.List的东西,但它可能是可变的,也可能是不可变的。 (实际上,我认为这取决于您传递0、1或多个项。 ,但是在未来的Kotlin版本中,确切的实现可能会发生很大变化,所以您不应该做任何假设)。
类似地,mutableListOf()返回kotlin.MutableList的一些实现,但没有承诺哪个实现。
实际上,如果您需要一个可变的列表,那么您应该显式地创建一个列表(或者创建一个特定的类,比如ArrayList,或者更好的方法是调用mutableListOf()并让它选择最合适的类型),如果您不能控制列表的创建,那么--正如您所说--您可以调用toMutableList() (尽管这可能会创建一个不必要的副本)。
发布于 2022-08-30 21:06:44
列表几乎总是可以转换为MutableLists (除非您自己编写了实现Kotlin列表而不是MutableList的类),因为大多数(可能全部?)对于生成列表的Kotlin函数,请在幕后使用Java列表,而Java列表始终等同于Kotlin MutableList。Java使列表不可变的方法是在运行时尝试修改异常时抛出异常,这就是为什么会发生崩溃。
基本上,您不应该将转换为,因为它本质上是不安全的。类将MutableLists的只读视图公开为列表是一种常见的设计模式,以防止它们在外部发生变异。这就是Kotlin在处理不可变异的列表时如何保护您免受崩溃的方法。如果您通过转换来颠覆这种设计模式,有时它将在运行时成功,因为底层列表不是Java不变的列表实现,然后您将触发很难跟踪的bug。
如果您想探索源代码,在IntelliJ IDEA或Android中,您可以通过Ctrl+click函数查看它的源代码。因此,在本例中,您可以使用listOf完成这一操作,并按下命令,直到找到用Java生成的列表实现为止。
https://stackoverflow.com/questions/73548084
复制相似问题