Coming from different languages, this seems to confuse me.
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
still has original values [A,B,C], I believe this is due to immutability, but does this mean I have created three garbage collectible Strings when I iterated through the array?
Yet this code does modify array?
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
}
This code
for (String n : names){
n = new String(n+"hello");
}
is same as
for (int i = 0; i<names.length; i++){
String n = names[i];
n = new String(n+"hello");
}
So as you see assigning n
new value can't affect array. And yes, at end of each iteration String created via new String(n+"hello");
will be eligible for garbage collection.
But since n
by default holds same object as names[i]
you can use it to change state of held object. For instance if your array would be array of Persons
, via n
you would be able to change property like age
of stored Person
n.setAge(42);
You can also assign new value to n
,
n = new Person("Jack", 40);
but this doesn't mean that you are assigning new value to names[i]
because n
and names[i]
are different variables.
Maybe this will help you a little
when n = names[i]
situation looks like this:
names[i] ----+ +--------+
| | Person |
+------>+--------+
| | name | //Adam
n ----+ | age | //30
+--------+
so both variables (references) hold same instance, which allows you to manipulate it from both variables (if you change name
or age
via n
you will be also to see this change also via names[i]
because they hold same object)
But if you do
n = new Person("Jack", 42);
you are assigning new object only to n
, not to names[i]
, so situation will be
+--------+
| Person |
names[i] ----------->+--------+
| name | //Adam
| age | //30
+--------+
+--------+
| Person |
n ----------->+--------+
| name | //Jack
| age | //42
+--------+
which means that array (names[i]
) doesn't change.
In short via n
you can't put new
elements to array, but you can change state of existing elements.
In short, yes you did create 3 GC eligible String
objects inside the loop, because while you created the 3 String
's, they are immediately out of context when the loop exits, because the variable n only exists within the for each loop.
As a side note, you can't change the values within the names array while you are iterating over it using a for-each construct.
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;
If you do try to modify names
within the loop it should throw a ConcurrentModificationException. The String
's that were created within the loop, are out of context as soon as you exit the loop, and so are eligible for GC.
Updated Code Explanation:
Your updated code works because you are accessing each object within the array individually, changing each object which then implicitly updates the value in the array. Using a normal for loop to do this is fine, because you are using something external to the object you are iterating over to control the iteration (in this case a variable called i).
You are essentially doing this:
for(int i = 0; i < cars.length; i++){
cars[i].color = "black";
}
Because you don't use Car c = new Car(cars[i]);
you get the actual Car
object instance that is contained inside the array, not a copy of the Car
object contained inside the array which is what you seem to be expecting to get.
You won't get a different object reference back unless you specifically invoke a constructor. For example you could do the following:
for(int i = 0; i < cars.length; i++){
Car c = new Car();
c.setColor(cars[i].getColor());
}
which would not modify the value of the car object inside the cars
array.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With