Why is it possible to modify an ArrayList of Custom Objects in a for...each loop

Kinnison84 :

We have a simple Custom Object :

public class CustomObject {
    public CustomObject(int myIntNumber, String myString) {
    this.myIntNumber = myIntNumber ;
    this.myString = myString;    
    }

    private int myIntNumber;
    private String myString;

    public void setMyIntNumber(int myIntNumber) {
    this.myIntNumber = myIntNumber;
}

public int getMyIntNumber() {
    return myIntNumber;
}

public void setMyString(String myString) {
    this.myString = myString;
}

public String getMyString() {
    return myString;
}


    public String toString() {
        return "CustomObject [" + String.valueOf(myIntNumber)  + ", "+ myString+"]" ;  
    }
}

and, we try to modify an ArrayList of such objects with a for...each loop. Why do the objects in the list get modified, when an ArrayList of String objects or of Integer objects cannot be modified in this way ?

My test code:

import java.util.ArrayList;

public class TestTraveringListModification {

    public static void main(String[] args) {

    ArrayList<String> sList  = new ArrayList<String>();
    sList.add("String a");
    sList.add("String b");
    sList.add("C");
    sList.add("D");
    sList.add("String f");
    sList.add("String e");

    System.out.println("Before: "+sList);
    for (String s : sList) {
        s="asdf" ;

    }

    System.out.println("After: "+ sList);

    ArrayList<CustomObject> objL = new ArrayList<CustomObject> () ;
    objL.add(new CustomObject (1, "test") );
    objL.add(new CustomObject (2, "jim") );
    objL.add(new CustomObject (20, "dec") );
    objL.add(new CustomObject (60, "what") );
  System.out.println("before: "+ objL );
    for(CustomObject co : objL ){    
        co.setMyIntNumber(-1);
        co.setMyString("modified String");
    }
    System.out.println("after: "+objL);


    ArrayList<Integer> numList = new ArrayList<Integer>(); 

    numList.add(1);
    numList.add(3);
    numList.add(5);
    numList.add(67);
    numList.add(9598);

    System.out.println("before: "+ numList);

    for (Integer i : numList){
        i = 8; 
    }
    System.out.println("after: "+ numList);

}
}

Running this will produce the following output:

Before: [String a, String b, C, D, String f, String e]

After: [String a, String b, C, D, String f, String e]

before: [CustomObject [1, test], CustomObject [2, jim], CustomObject [20, dec], CustomObject [60, what]]

after: [CustomObject [-1, modified String], CustomObject [-1, modified String], CustomObject [-1, modified String], CustomObject [-1, modified String]]

before: [1, 3, 5, 67, 9598]
  • List item

    after: [1, 3, 5, 67, 9598]

So, why is it that I can modify objL and not sList or numList ?

Amadan :

Because reassignment and mutation are two different things.

s = "asdf" will change what s is refering to. It used to contain a reference to a member of sList, now it refers to "asdf". The change has nothing to do with the member of sList.

Similar with i and numList, though not completely exactly same. numList contains Integer objects, autoboxed from 1, 3, 5... for will assign the Integer objects value to i. If you then change the value of i to (autoboxed) Integer(8), it also doesn't affect numList any.

However, with co and objL, you do a very different thing. Instead of reassigning co to another object (which would not affect objects in objL), you chose to invoke methods on co, which then happened to change their state. Note that here you are not modifying objL, you're modifying the objects it contains.

The key insight is that i, co and s are not elements of the respective lists. They contain values that might be elements of the lists (but again in case of autounboxing, this too does not hold).

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=112365&siteId=1
Recommended