我想知道以下循环是否创建了对象的副本,而不是给我一个对它的引用。原因是,因为第一个例子没有分配我的数组对象,但第二个例子没有。
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();
}
答案 0 :(得分:15)
Java的工作方式与许多其他语言略有不同。第一个示例中的o
只是对对象的引用。
当你说o = new MyObject()
时,它会创建一个MyObject类型的新Object,并引用o
到该对象,而o
引用objects[index]
之前。
也就是说,objects [index]本身只是对内存中另一个对象的引用。因此,为了将对象[index]设置为新的MyObject,您需要更改对象[index]指向的位置,这只能通过使用对象[index]来完成。
图片:(我可怕的绘画技巧:D)
说明: 这大致是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]
我们不需要注意增加计数器,这就是每个循环的美感。