Java: For-Each循环和引用
Java中的For-Each循环和引用
在Java中,我们经常使用For-Each循环来遍历数组或集合。然而,有时候我们可能会遇到一些问题,这篇文章将讨论一个常见的问题以及解决方法。
问题描述:
我们先来看一个例子:
MyObject objects[] = new MyObject[6]; for(MyObject o: objects) { // 构造一个新的MyObject对象,并将引用赋值给迭代变量o。然而,这没有持久的效果, // 因为在下一次迭代中,foreach循环将自动将下一个值赋给迭代变量。 o = new MyObject(); }
在这个例子中,我们尝试使用For-Each循环来为数组中的每个元素创建一个新的MyObject对象,并将引用赋值给迭代变量o。然而,这样做是无效的,因为在下一次迭代中,迭代变量o将被自动赋予下一个值,而不是我们创建的新对象的引用。
解决方法:
为了解决这个问题,我们可以改用传统的For循环来遍历数组,并将新创建的对象的引用分配给数组的相应元素。例如:
MyObject objects[] = new MyObject[6]; for(int i = 0; i < objects.length; i++) { // 构造一个新的MyObject对象,并将引用存储到数组objects[]的第i个槽中: objects[i] = new MyObject(); }
在这个例子中,我们使用传统的For循环来遍历数组,并使用索引i来访问每个数组元素。这样,我们可以将新对象的引用分配给数组的相应元素,确保我们创建的新对象在迭代之后仍然可用。
在使用For-Each循环时,需要注意不能直接为数组或集合中的元素赋值,因为这不会持久地改变数组或集合的内容。为了解决这个问题,我们可以改用传统的For循环,并使用索引来访问和修改数组或集合的元素。
Java中的for-each循环和引用的问题起因于在foreach循环中将引用设置为其他值时,并不会改变数组的内容。解决方法是使用普通的for循环来遍历数组,并直接修改数组的内容。以下是具体内容:
短答案是:是的,确实发生了类似复制的操作。
长答案是:你在Java中使用的foreach循环实际上是语法糖,等价于下面的代码:
MyObject objects[] = new MyObject[6]; Iteratorit = objects.iterator(); while (it.hasNext()) { MyObject o = it.next(); // 上述三行代码对应于foreach循环 // foreach循环内的代码 o = new MyObject(); }
从上述代码可以看出,将引用设置为其他值并不会改变数组的内容。
因此,解决这个问题的方法是使用普通的for循环来遍历数组,并直接修改数组的内容。
Java中的ForEach循环和引用
Java与许多其他语言的工作方式略有不同。在第一个示例中,o只是对对象的引用。
当你说o = new MyObject()时,它会创建一个类型为MyObject的新对象,并将o引用到该对象,而之前o引用了objects[index]。
也就是说,objects[index]本身只是指向内存中另一个对象的引用。因此,为了将objects[index]设置为一个新的MyObject,你需要改变objects[index]指向的位置,这只能通过使用objects[index]来完成。
这是大致描述Java内存管理工作方式的图示。不完全准确,但可以大致理解。你有一个objects数组,引用A1。当你访问objects数组时,从开始的引用点(A1)开始,向前移动X个块。例如,引用索引1会将你带到B1。然后,B1告诉你要查找A2处的对象。A2告诉你它在C2处有一个字段。C2是一个整数,一个基本数据类型。搜索完成。
o不引用A1或B1,而是引用C1或C2。当你说new ...时,它会创建一个新的对象,并将o放在那里(例如,在槽位A3中)。它不会影响A1或B1。
当然,这是有道理的。所以在第一个示例中,o有点像C++指针,因为它本身是一个变量,因此它的值是另一个变量的地址。因此,当分配任何东西给它时,设置的是变量本身,而不是它指向的内容。
确切地说,与C++不同,Java在指针控制方面没有太多的功能。变量引用内存中的位置,而"="重新引用它们。你不能在你引用的位置创建一个新的变量。但是,你可以改变这个变量。如果o已经被初始化,o.x是一个字段,你可以改变o.x的指向,从而重新分配o.x。
希望这能帮助你理解。