来自不同的语言,这似乎让我感到困惑。
String [] names = new String[]{"A","B","C"};
for (String n : names){
n = new String(n+"hello");
}
System.out.println(Arrays.toString(names)); // [A, B, C]
names
仍然有原始值[A,B,C],我相信这是由于不变性,但这是否意味着我在遍历数组时创建了三个垃圾收集字符串?
然而这段代码确实修改了数组?
Car [] cars = { new Car("red"), new Car("green") };
for(int i=0; i<cars.length; i++){
Car c = cars[i];
c.color ="black";
}
for(int i=0; i<cars.length; i++){
Car c = cars[i];
System.out.println(c.color); //prints black, black
}
答案 0 :(得分:6)
此代码
for (String n : names){
n = new String(n+"hello");
}
与
相同for (int i = 0; i<names.length; i++){
String n = names[i];
n = new String(n+"hello");
}
因此,当您看到分配n
时,新值无法影响数组。是的,在每次迭代结束时,通过new String(n+"hello");
创建的字符串将有资格进行垃圾回收。
但是,由于n
默认包含与names[i]
相同的对象,因此您可以使用它来更改所持对象的状态。例如,如果您的数组是Persons
数组,则可以通过n
更改存储的人员age
之类的属性
n.setAge(42);
您还可以为n
,
n = new Person("Jack", 40);
但这并不意味着您要为names[i]
分配新值,因为n
和names[i]
是不同的变量。
也许这会对你有所帮助
n = names[i]
情况如下:
names[i] ----+ +--------+
| | Person |
+------>+--------+
| | name | //Adam
n ----+ | age | //30
+--------+
因此两个变量(引用)都拥有相同的实例,允许您从两个变量中操作它(如果您通过name
更改age
或n
,您也会看到这个也可以通过names[i]
进行更改,因为它们拥有相同的对象)
但如果你这样做
n = new Person("Jack", 42);
您只将新对象分配给n
,而不是names[i]
,因此情况将是
+--------+
| Person |
names[i] ----------->+--------+
| name | //Adam
| age | //30
+--------+
+--------+
| Person |
n ----------->+--------+
| name | //Jack
| age | //42
+--------+
表示数组(names[i]
)没有变化。
简而言之,通过n
,您无法将new
元素添加到数组中,但您可以更改现有元素的状态。
答案 1 :(得分:2)
简而言之,是的,您确实在循环中创建了3个符合条件的String
个对象,因为当您创建3个String
时,它们会在循环退出时立即脱离上下文,因为变量n仅存在于每个循环中。
作为旁注,当您使用for-each构造对其进行迭代时,您无法更改names数组中的值。
String [] names = new String[]{"A","B","C"};
for(String n : names){
//There is no way you can modify the array within the loop,
//You can only read out of it.
//Because n only has meaning inside the loop, any changes to it,
//only have meaning inside the loop.
n = "The Spanish Inquisition";
//No one expects the above assignment to change the value of
//names array value that n was originally, because n is just a
//reference of the value held within the array.
}
return names;
如果您尝试在循环中修改names
,则应抛出ConcurrentModificationException。在循环中创建的String
一旦退出循环就会脱离上下文,因此符合GC的条件。
更新的代码说明:
您更新的代码有效,因为您正在单独访问数组中的每个对象,更改每个对象,然后隐式更新数组中的值。使用普通for循环来做这件事很好,因为你正在使用迭代的对象外部来控制迭代(在这种情况下是一个名为i的变量)。
你基本上是这样做的:
for(int i = 0; i < cars.length; i++){
cars[i].color = "black";
}
因为你不使用Car c = new Car(cars[i]);
,你得到数组中包含的实际Car
对象实例,而不是数组中包含的Car
对象的副本是你似乎期待得到的。
除非您专门调用构造函数,否则您将无法获得不同的对象引用。例如,您可以执行以下操作:
for(int i = 0; i < cars.length; i++){
Car c = new Car();
c.setColor(cars[i].getColor());
}
不会修改cars
数组中的car对象的值。
答案 2 :(得分:1)
不,您在任何时候都没有更改数组names
。 n
只是一个变量,用于迭代names
中包含的所有值。假设foreach是一个有效的关键字......您只需要for