简体   繁体   中英

Method changes object

Can you explain me such behavior of this code:

class Test{
    public List<String> change(List<String> s){
        List<String> tmp = s;
        tmp.add("test");
        return tmp;
    }

    public Integer change(Integer s){
        Integer tmp = s;
        tmp++;
        return tmp;
    }
}


public class Main {

    public static void main(String[] args)  {

        List<String> l = new ArrayList<String>();
        Integer i = new Integer(10);

        Test t = new Test();

        System.out.println(l);
        t.change(l);
        System.out.println(l);

        System.out.println(i);
        t.change(i);
        System.out.println(i);

    }
}

And the result is:

[]
[test]
10
10

Why my list is changed even if inside change() method I create tmp variable and ascribe to it passed argument and my Integer is not change in the same situation?

The trick is here:

    Integer tmp = s;
    tmp++;

This is roughly equivalent* to:

    Integer tmp = s;
    int tmp_unboxed = tmp.intValue;
    tmp_unboxed++;
    tmp = new Integer( tmp_unboxed );

The Integer is unboxed to an int , then the int is incremented and finally the result is boxed into a different Integer object.

As you can see, the original integer hasn't been modified, a new one was created instead. Whereas in the list example you modify the original list.

*I oversimplified the situation massively to get the point across easier: in particular you don't always get a brand new Integer instance, but you always get a different Integer instance than what you started with..

It is because Integer (same as String, Double etc.) is immutable. It means you cant change the value of that object.

So what happens here?

Integer tmp = s;
        tmp++;

At this line Integer tmp = s; , the instance of Integer (we can call it X) is in memory and reference to it is stored in variable s . You copy this reference of X into variable tmp .

In this line tmp++; , because Integer is immutable, the new instance Y is created in memory, it is given value of instance X and then it is incremented and reference to it is then stored in variable tmp .

Variable X is still in memory with unchanged value.

Integer object is immutable. Capture the result from

int returnedObject = t.change(i);

and print returnedObject , you will see modified object

On the other hand list object is mutable. Thats why change is reflected in same object itself

This is due to two features of java: autoboxing and pass-by-reference.

Pass-by-reference means that if an Object is used as parameter of a method, it's location in the memory is passed to the method. Thus the List , which is passed as parameter gets modified.

The Integer is passed by reference aswell, but here autoboxing applies. Integer itself is an Object and doesn't support operators; Integer is immutable! Autoboxing transforms an Integer , or the object representation of a primitive type to the primitive type. Thus the Integer is transformed into an int and the int is modified. This action doesn't affect the Integer -object though. What basically happens with the Integer in change can be roughly described this way:

public Integer change(Integer s){
    //store reference to `s` in tmp
    Integer tmp = s;

    //unbox tmp and increment
    tmp++;

    //return tmp
    return tmp;
}

Unboxing:
int unboxed = tmp.intValue();
unboxed++;
tmp = new Integer(unboxed);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM