Reputation: 113
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?
Upvotes: 0
Views: 62
Reputation: 49804
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..
Upvotes: 3
Reputation:
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);
Upvotes: 1
Reputation: 23049
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.
Upvotes: 1
Reputation: 34424
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
Upvotes: 1