当ArrayList重新分配时,为什么Java变量不会失效?

时间:2017-04-19 05:39:49

标签: java oop

我想知道Java的运行时如何知道对象的位置。为什么这段代码有效:

A类

class A{
    int id;
    A(int i){
        id = i;
    }
}

主要

ArrayList<A> array = new ArrayList<>();
for(int i=0; i<10; i++){
    array.add(new A(i));
}

A fifth = array.get(5); // this object will be reallocated soon

for(int i=10; i<1000000; i++){
    array.add(new A(i));
}

System.out.println("it's still alive " + fifth.id); // works, but why?

变量名称究竟与实际对象绑定的是什么?这是在运行时管理的吗?

编辑:我只是自己弄清楚了答案,因为ArrayList下面的数组包含指向对象的指针,但这些对象本身一直都在同一个地点。只有指针数组移动。我整个晚上都在做C ++,而我的思绪一直在考虑包含非堆元素的向量。这就是为什么我混淆了这一点。

3 个答案:

答案 0 :(得分:3)

您混淆的原因是您认为ArrayList存储对象 - 但它不存在,它只存储引用(&#34;指针&#34; )对这些对象。因此,当内部数组扩展/重新分配时,对象仍然在同一个地方。

让我们来看看你的例子:

  • 让我们假设array的起始数组位于100
  • 假设i=5 new A(i)在特定位置创建了A,请说123。然后array数组的fith条目为A@123
  • fifth = array.get(5)只需复制引用,因此fith包含A@123
  • array必须增长其数组时,它会创建一个新数组,例如在200。然后,它会将所有现有条目复制到新位置,包括位置5的A@123
  • 我们首先创建的对象仍位于其原始位置123,因此A@123中包含的引用fith仍然有效

对象只会在垃圾收集过程中被移动,但这在iavanish的回答中有所涉及。

答案 1 :(得分:2)

我已经进一步注释了您的源代码。 :)

ArrayList<A> array = new ArrayList<>(); // allocates a single ArrayList object 
// the ArrayList contains an array of references (pointers), all null
for(int i=0; i<10; i++){
   A temp = new A(i); // allocates a new A
   array.add(new A(i)); // stores the pointer to A in the list
}

A fifth = array.get(5); // This object was allocated before, and is unchanged

for(int i=10; i<1000000; i++){
      A temp = new A(i); // Allocates a new A
      array.add(); // Stores the pointer in the list
      // Internally, the List may reallocate its backing array, but it 
      // is an array of References (pointers), not the A objects themselves
}

System.out.println("it's still alive " + fifth.id); // fifth was allocated in line 4
// and is still reachable

List从不包含A本身的实例,只引用它们。因此,List的内部内存管理不会影响其内容。

答案 2 :(得分:0)

这是您编辑的答案,因此它只是您问题的补充:

实际上Java中的引用根本不像C ++指针,还有一个额外的间接层 - 对象本身的地址一直在移动(由于压缩垃圾收集),但引用仍然有效。