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