符合GC条件的Java For Each循环内创建的字符串

时间:2015-01-28 03:24:31

标签: java arrays

来自不同的语言,这似乎让我感到困惑。

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
    }

3 个答案:

答案 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]分配新值,因为nnames[i]是不同的变量。

也许这会对你有所帮助

n = names[i]情况如下:

names[i] ----+       +--------+
             |       | Person |
             +------>+--------+
             |       | name   | //Adam 
       n ----+       | age    | //30
                     +--------+

因此两个变量(引用)都拥有相同的实例,允许您从两个变量中操作它(如果您通过name更改agen,您也会看到这个也可以通过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)

不,您在任何时候都没有更改数组namesn只是一个变量,用于迭代names中包含的所有值。假设foreach是一个有效的关键字......您只需要for