11

Ok. I'm completely aware that all values in Java are passed by value. But this example does not behave as I expected:

public class Test {

private static void changeInteger(Integer x) {
    x = 5;
}

public static void main(String[] args) {
    Integer x = 0;
    changeInteger(x);
    System.out.println(x);
}

}

Since I'm passing wrapper class to the changeInteger Method, I'm passing its address, so, after executing function that should affect my x variable and set it to 5. But eclipse says that output is still 0. What did I understand wrong?

Filip
  • 2,244
  • 2
  • 21
  • 34

6 Answers6

8

Consider this example:

class Wrapper {
    int n;
    public Wrapper(int k) { n = k; }
    public String toString() { return ""+n;}
    public static Wrapper valueOf(int k) { return new Wrapper(k); }
}

Now let us replace Integer in your code with the Wrapper class above:

private static void changeInteger(Wrapper x) {
    x = Wapper.valueOf(5);
}

public static void main(String[] args) {
    Wrapper x = Wrapper.valueOf(0);
    changeInteger(x);
    System.out.println(x);
}

Since you mentioned that you know about passing by value, I hope that it is clear why this code does what it does.

Now let's go back to your code. Under the hood, it is exactly the same code. The only difference is that you do not call Wrapper.valueOf: the compiler does it for you through autoboxing. Once you realize that this is what is going on, the issue should be clear to you.

ByteCode of changeInteger() to show that Integer.valueOf() is called :

private static void changeInteger(java.lang.Integer);
  Code:
   Stack=1, Locals=1, Args_size=1
   0:   iconst_5
   1:   invokestatic    #16; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In
  teger;
  .... // some other code
TheLostMind
  • 35,966
  • 12
  • 68
  • 104
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
4

With x = 5; you assign a new value to x inside changeInteger(). You are not changing the value of the current Integer object.

The value of x outside the method is not affected.

micha
  • 47,774
  • 16
  • 73
  • 80
  • OP created object before passing to the method. – Suresh Atta Sep 16 '14 at 10:06
  • yes but `x = 5` creates a new `Integer` objects and assigns it to `x` inside `changeInteger()`. After that, the original reference to `x` is only available in `main` – micha Sep 16 '14 at 10:07
  • 2
    More like `x = Integer.valueOf(5)` which will pick up value from the cache rather than creating a new wrapper object. – Sanjay T. Sharma Sep 16 '14 at 10:09
  • 1
    This is wrong. `x=5` is not same as `x = new Integer(5)`. It is same as `x= Integer.valueOf(5)` a new Integer object will not be created. Like @SanjayT.Sharma says, the value `5` from the local cache will be reused. – TheLostMind Sep 16 '14 at 11:22
  • You are both right. My intention was to show that `x = 5` assigns a new value to `x` (instead of changing the value of `Integer` object). I removed this part of the answer. – micha Sep 16 '14 at 11:48
  • @micha - +1. And I removed my downvote :) – TheLostMind Sep 16 '14 at 12:17
2

You get puzzled by the autoboxing function of java. You cannot assign a primitive value to an objec. When you call x=5 it creates a new Integer object with 5 value and assignes its reference to x. But this affects only the parameter in the scope of changeIngeger, the original object with 0 and the reference of x in main scope are untouched.

holap
  • 438
  • 2
  • 18
1

Your problem is the fact that Java is pass-by-value not by-reference so the x in the method is not the same x of main. The fact that Integer is an immutable class, here doesn't change anything.

Marco Acierno
  • 14,682
  • 8
  • 43
  • 53
  • 1
    I think this is wrong. X as an argument has the same address as the outer X, but fact that wrappers are immutable are crucial here, since regular assigment is translated as X = new Integer(5), and we are putting value onto the new address and cannot reach it from outer X. – Filip Sep 16 '14 at 10:48
1

All Java parameters are passed by value. For all non-primitive types, the value contains a reference to the object that's passed.

For your piece of code, the Integer object is stored at location A in memory. Another location B in memory represents the main's variable x and stores a value A.

For the changeInteger call, a new location C is created and a value in B (which is A) gets copied to it. This is the local x of the changeInteger function.

With the assigning, you create a new variable stored at D and its location is assigned to C. Then you return from the method.

You can see that A and B isn't modified anywhere and thus the value remains unchanged.

Danstahr
  • 4,190
  • 22
  • 38
0

Keeping as simple as it is, All Java Wrapper classes are Immutable. So you cannot seeing the change.

If you want to see the change, just return from method (not main) and assign it back.

Suresh Atta
  • 120,458
  • 37
  • 198
  • 307
  • 1
    `All Java Wrapper classes are Immutable. So you cannot seeing the change.` That's not the reason. The reason is that java is pass-by-value, so you can't change a parameter's value this way, as the new value will be discarded when the method finishes its execution. – BackSlash Sep 16 '14 at 10:11