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.