Kotlin 集合中的任何类型与嵌套具体类型

Joo*_*o21 0 string collections any kotlin

使用 Any 作为集合类型是否比使用具体类型消耗更少的内存?

\n

认为

\n
val list1 = listOf<Any>("ABC", "DEF", "GHI", "JKL", "MNO")\nval list2 = listOf<String>("ABC", "DEF", "GHI", "JKL", "MNO")\n
Run Code Online (Sandbox Code Playgroud)\n

我想知道是否list1消耗的内存比list2类型String分配内存来存储其属性(例如size)要少

\n

list1那么,如果我不使用任何String类型函数,是不是更好?

\n


\n编辑

\n如果我想使用集合中的其他类型怎么办?

\n
list = listOf<Any>("ABC", 123, 12.34)\n
Run Code Online (Sandbox Code Playgroud)\n

它比效率更高吗

\n
list = listOf<String>("ABC", "123", "12.34")\n
Run Code Online (Sandbox Code Playgroud)\n



\n编辑 2
\n感谢@Jo\xc3\xa3o Dias 和@gidds

\n

正如@gidds 所说:

\n
\n

该列表不直接包含 String 对象,或其包含引用的任何对象 \xe2\x80\x94 。

\n
\n
\n

String 引用的大小与 Any 引用或任何其他类型的引用完全相同。\xe2\x80\x82

\n
\n

因此,由于类型擦除List<String>,和List<Any>是完全相同的- @Jo\xc3\xa3o Dias 指出- 编译时和运行时类型不同\n

\n

但是,这是否意味着

\n
val list1 = listOf<Any>("ABC", "DEF", "GHI")\n
Run Code Online (Sandbox Code Playgroud)\n

\n
val list2 = listOf<String>("ABC", "DEF", "GHI")\n
Run Code Online (Sandbox Code Playgroud)\n

消耗相同的内存

\n
val list3 = listOf<List<List<List<String>>>>(\nlistOf(listOf(ListOf("ABC"))), \nlistOf(listOf(ListOf("DEF"))), \nlistOf(listOf(ListOf("GHI")))\n)\n
Run Code Online (Sandbox Code Playgroud)\n

AFAIKString基本上是 的集合Char。AString包含对 的引用Char。由于 Kotlin 中的所有内容都是对象,因此Char内部的每个对象都String应该包含对堆中值的引用,到目前为止我正确吗?\n如果是这种情况,那么消耗比拥有超过 1 个引用更多的内存

是否有意义。List<String>List<Any>List<String>

\n

gid*_*dds 5

到目前为止尚未解决的一点是列表不直接包含String对象,或者它包含引用的Any对象 \xe2\x80\x94 。

\n

引用的String大小与引用或任何其他类型的引用完全相同Any。\xe2\x80\x82(该大小取决于运行代码的 JVM 的内部结构;它可能是 4 或 8 个字节。\xe2\ x80\x82请参阅这些 问题。)

\n

当然,被引用的对象也会在堆中占用自己的空间;但这两种情况都是一样的。

\n
\n

编辑添加:

\n

List如何实现和的内部细节String与原始问题无关。\xe2\x80\x82(这很好,因为它们在实现之间有所不同。)\xe2\x80\x82JVM 语言(例如 Kotlin)只有两种值:基元(IntShortLongByteCharDoubleFloatBoolean)和引用(对象或数组)。

\n

因此,任何集合,如果它不是基元集合,都是引用集合。\xe2\x80\x82这适用于所有List实现。\xe2\x80\x82因此,您的list1list2对象的大小将完全相同,仅取决于他们持有(或可以持有)的参考文献数量,而不是这些参考文献中的内容。

\n

如果你想要更深入的了解,list1是一个参考,指向一个实现该List接口的对象。\xe2\x80\x82有很多不同的实现,我不知道 Kotlin 会选择哪一个(再说一次,可能会在版本之间发生变化),但比如说它是一个ArrayList.\xe2\x80\x82,它至少有两个属性:一个大小(可能是一个Int)和一个对数组的引用,该数组保存对列表中的项目。\xe2\x80\x82(该数组通常会大于列表的当前大小,这样您就可以添加更多项目,而不必每次都重新分配数组;列表的当前大小数组被称为列表的容量。)\xe2\x80\x82如果这些项是Strings,则确切的内部表示取决于 JVM 版本,但它可能是一个至少具有三个属性的对象Char:一个Int给出数组中字符串的起始索引,另一个Int给出长度。

\n

但正如我所说,随着时间的推移以及 JVM 版本之间的细节会发生变化。\xe2\x80\x82 不变的是,它是引用List的集合,并且引用的大小不依赖于其类型。\ xe2\x80\x82因此,引用列表String(所有其他条件相同)将与对这些相同字符串的引用列表占用完全相同的空间Any

\n

(而且,正如其他地方提到的,由于运行时的类型擦除,JVM 没有类型参数的概念,因此对象实际上是相同的。)

\n

当然,\xe2\x80\x98深度大小\xe2\x80\x99(列表及其包含的对象占用的总堆空间)将取决于这些对象\xe2\x80\x94的大小,但在在我们正在讨论的情况下,这些是完全相同的String对象,因此大小也没有差异。

\n