0

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?

user3056857
  • 113
  • 4
  • 2
    Because `tmp++` creates a new `Integer` instance instead of changing the original one. – biziclop Nov 10 '15 at 13:57
  • 1
    Possible duplicate of [Is Java "pass-by-reference" or "pass-by-value"?](http://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value) – Jaroslaw Pawlak Nov 10 '15 at 14:08

4 Answers4

3

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..

biziclop
  • 48,926
  • 12
  • 77
  • 104
1

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.

libik
  • 22,239
  • 9
  • 44
  • 87
1

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

M Sach
  • 33,416
  • 76
  • 221
  • 314
1

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);
  • 1
    Please, please, pretty please. Java is strictly **pass-by-value**. Always. You may get **pass-reference-by-value** but never **pass-by-reference**. – biziclop Nov 10 '15 at 14:03
  • 1
    http://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value – biziclop Nov 10 '15 at 14:08
  • @biziclop you're right. Though that's basically hairsplitting in this context. I've quite often seen (actually most of the time) "pass-by-reference" instead of "pass-reference-by-value". –  Nov 10 '15 at 14:14
  • In this context it indeed can be seen as hairsplitting but it's an important distinction in general. Things can get really confusing really quickly if we don't use the correct terminology, particularly from someone coming from a language like C++, which **does* support pass-by-reference. – biziclop Nov 10 '15 at 14:25