假设以下代码:
ArrayList<A> aList = new ArrayList<>();
for(int i = 0; i < 1000; ++i)
aList.add(new A());
A anElement = aList.get(500);
for(int i = 0; i < 100000; ++i)
aList.add(new A());
之后 anElement 仍然正确引用 aList[500],即使 ArrayList 在第二个 for 循环期间可能多次重新分配其数据。这个假设是否不正确?如果不正确,Java 如何设法让 anElement 仍然指向内存中的正确数据?
我的理论是,要么不是释放 anElement 引用的内存,而是该内存现在指向当前 aList 数据,要么在增长数组时更新 anElement 的引用。然而,这两种理论都对空间/时间性能产生了非常糟糕的影响,所以我认为它们不太可能。
编辑:
我误解了数组如何存储元素,我以为它们直接存储它们,但实际上它们存储引用,这意味着 anElement 和 aList[500] 都指向堆上的某个对象,解决了我无法理解的问题!
最佳答案
当内部存储 ArrayList 元素的数组变满时,将创建更大的新数组,并将前一个数组中的所有元素复制到相同索引处的新数组中,现在有新元素的空间。垃圾收集器将删除以前不再需要的数组。
您可能想看一下 ArrayList
的实现代码 here查看其“幕后”工作原理的详细信息。
代码中的第二个循环,在第 1000 个元素之后添加了接下来的 100000 个元素,因此现在 aList
中有 101000 个元素,前 1000 个元素没有移动到任何地方。使用 get()
方法,您只能读取该元素,不会从该 ArrayList
中移动或删除任何内容。
请注意,ArrayList
并不像数组那样工作(例如 A
数组是 A[]
),而且它不是固定的-size 集合 - ArrayList 在添加或删除元素时更改其大小 - e。 G。如果删除索引 0 处的元素 (aList.remove(0);
),则存储在索引 1000 处的元素现在存储在索引 999 处,并且 ArrayList
的大小也存储在索引处从 1000 更改为 999。
关于java - 对 ArrayList 中稍后移动的元素的引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48948013/