Java:For-Each循环和引用

时间:2012-02-16 04:38:51

标签: java object loops for-loop

我想知道以下循环是否创建了对象的副本,而不是给我一个对它的引用。原因是,因为第一个例子没有分配我的数组对象,但第二个例子没有。

MyObject objects[] = new MyObject[6];
for (MyObject o: objects) {

    o = new MyObject();
}

MyObject objects[] = new MyObject[6];
for(int i = 0; i < objects.length; i++) {

    objects[i] = new MyObject();
}

7 个答案:

答案 0 :(得分:15)

Java的工作方式与许多其他语言略有不同。第一个示例中的o只是对对象的引用。

当你说o = new MyObject()时,它会创建一个MyObject类型的新Object,并引用o到该对象,而o引用objects[index]之前。

也就是说,objects [index]本身只是对内存中另一个对象的引用。因此,为了将对象[index]设置为新的MyObject,您需要更改对象[index]指向的位置,这只能通过使用对象[index]来完成。

图片:(我可怕的绘画技巧:D)

enter image description here

说明: 这大致是Java内存管理的工作原理。无论如何,不​​完全是粗略的。你有对象,引用A1。当您访问对象数组时,从开始参考点(A1)开始,然后向前移动X块。例如,引用索引1会将您带到B1。 B1然后告诉你,你正在A2寻找对象。 A2告诉你它有一个位于C2的字段。 C2是整数,基本数据类型。搜索已完成。

o不引用A1或B1,而是引用C1或C2。当你说new ...时,它会创建一个新对象并放在那里(例如,在插槽A3中)。它不会影响A1或B1。

如果我能清楚一点,请告诉我。

答案 1 :(得分:9)

简短回答:是的,还有类似副本的内容。

长答案:您发布的Java foreach循环是

的语法糖
MyObject objects[] = new MyObject[6];

Iterator<MyObject> it = objects.iterator();
while (it.hasNext()) {
   MyObject o = it.next();
   // The previous three lines were from the foreach loop

   // Your code inside the foreach loop
   o = new MyObject();
}

正如desugared版本所示,设置一个等于foreach循环内部内容的引用不会改变数组的内容。

答案 2 :(得分:4)

我在每个例子中添加了一条评论,以澄清发生了什么。

第一个例子:

MyObject objects[] = new MyObject[6]; 
for(MyObject o: objects) { 

    // Construct a new object of type MyObject and assign a reference to it into 
    // the iteration variable o. This has no lasting effect, because the foreach
    // loop will automatically assign the next value into the iteration variable
    // in the the next iteration.
    o = new MyObject(); 
} 

第二个例子:

MyObject objects[] = new MyObject[6]; 
for(int i = 0; i < objects.length; i++) { 

    // Construct a new object of type MyObject and store a reference to it into the
    // i-th slot in array objects[]:
    objects[i] = new MyObject(); 
} 

答案 3 :(得分:3)

第一个不分配您的数组对象,因为foreach循环遍历集合中的元素。

当你输入foreach循环时,你的集合中没有任何元素,它只是一个初始化为6的空数组,因此不会有任何对象添加到你的数组中。

另外,请注意,即使您在数组中有元素,foreach循环也不会分配在它们之上:

o = new MyObject();

基本上意味着为o分配一个MyObject的新实例,但o本身不是数组objects的一部分它只是一个临时容器,用于迭代数组的元素,但在这种情况下,没有。

答案 4 :(得分:2)

当您明确声明要克隆对象时,对象仅被“复制”(此对象显式实现克隆功能)。

您似乎混淆了引用和名称。

在第一个示例中,在foreach中,本地o变量引用了存储来自objects的某个对象的内存区域。在进行o = new MyObject()时,会在其他内存区域初始化一个新的MyObject,然后重写o引用以指向这个新的内存区域。

在第二个示例中,通过编写objects[i] = new MyObject(),您说应该重写objects[i]引用,而不是某些本地o变量。

答案 5 :(得分:0)

我想提到的第一件事是非零长度数组总是可变的。并且在foreach循环内部

for(MyObject o in objects) 

它在每次迭代中的作用如下:

o = objects[0] // first iteration 
o = objects[1] // 2nd iteration

但在您的情况下,您将另一个对象分配给参考o。不是数组中的对象。它就像下面一样。

ObjeMyObject objects[] = new MyObject[6];
 MyObject o = Object[0];
 0 = new MyObject();

但是你的原始对象[0]仍然指向一个空对象。

答案 6 :(得分:0)

每次使用“new”运算符时,JVM都会创建一个新实例,它将被赋值给赋值运算符的左侧操作数。 对于每个循环或循环都无关紧要。 在每个循环中 for(MyObject O:Object) O将只创建一次MyObject,它将不会被实例化,Object数组中的值将保持在O中复制 喜欢

O = Object[0]
O = Object[1]
O = Object[2]
O = Object[3]
O = Object[4]
O = Object[5]

我们不需要注意增加计数器,这就是每个循环的美感。