10
public static void main(String[] args) {
    Integer i = new Integer(0);
    int[] arr = {1};
    p1(i);
    p2(arr);
    System.out.println(i);
    System.out.println(arr[0]);
}


public static void p1(Integer i) {
    i = 2;
}

public static void p2(int[] i) {
    i[0] = 2;
}

//output: 0, 2

How can I change the value of i like I change the value of arr?

cow12331
  • 245
  • 2
  • 3
  • 9

4 Answers4

18

You can't change the value of the variable i in main from within the p1 method, because the argument is passed by value: the parameter i in p1 is entirely separate from the i variable, it's just that they have the same value at the start of the method. Java always uses pass-by-value semantics - but when the parameter type is a class, it's a reference that is passed by value.

In fact, you're not changing the value of arr, either - it's a reference to the same array as before, but the value in the array has been changed. And that's what you can't do with Integer, because Integer is an immutable type.

If you want a mutable class like Integer, you could use AtomicInteger instead:

public static void main(String[] args) {
    AtomicInteger i = new AtomicInteger(0);
    modify(i);
    System.out.println(i);
}

private static void modify(AtomicInteger x) {
    x.set(2);
}

I would usually not do this, however - I usually try not to modify the objects that method parameters refer to. Instead, I write methods which compute a single result, and return that.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • That's not an answer to a problem, since AtomicInteger is not an Integer at all. And you answered wrongly. The argument is NOT passed by value. It is passed by reference since this is and Integer object (not the primitive int). – walkeros Oct 03 '14 at 19:49
  • 4
    @walkeros: No, it's really *not* passed by reference, because nothing is passed by reference in Java. Please read http://javadude.com/articles/passbyvalue.htm or some of the hundreds of questions on this topic on SO. I've explained that what the OP asked can't be done directly, so I've given an answer with a *similar* (but mutable) type. – Jon Skeet Oct 03 '14 at 19:50
  • Any boolean type like atomicinteger? – cow12331 Oct 03 '14 at 19:52
  • 1
    @cow12331: `AtomicBoolean`? – Jon Skeet Oct 03 '14 at 19:53
  • @Jon the reference to the object is passed by value which effectively acts as if object was passed by reference. I do not want to open discussion here, but pointing out in this case that objects are passed by value can trully mislead the person reading – walkeros Oct 03 '14 at 20:08
  • 3
    @walkeros: No, it doesn't act as if it were passed by reference - because otherwise changing `i` in the method *would* modify the caller's variable. (That's what pass-by-reference is all about.) Note that I didn't say that an object is passed by value - I said that the *reference* is passed by value. You're the one being misleading - and inaccurate - here, I'm afraid, by claiming Java uses pass-by-reference. Compare this with a language like C#, which *by default* acts like Java, but also allows pass-by-reference with the `ref` modifier. – Jon Skeet Oct 03 '14 at 20:10
  • @JonSkeet ok you wrote this sentence in right way. I should have written that reference is passed in comparison to that "it is passed by reference". You have my vote up in exchange;) – walkeros Oct 03 '14 at 20:32
  • thanks for mentioning "Integer is an immutable" for which it didn't get updated. – Chinmay Dec 10 '17 at 04:57
  • @walkeros Dude: you are talking to Jon Skeet – Christophe Roussy Feb 20 '18 at 10:18
5

You can use AtomicInteger, which allows changing, instead of Integer:

public static void main(String[] args) {
    AtomicInteger i = new AtomicInteger(0);
    p1(i);
    System.out.println(i);
}


public static void p1(AtomicInteger i) {
    i.set(2);
}
Dmitry Ginzburg
  • 7,391
  • 2
  • 37
  • 48
3

Simply put: You can't, because Integer is immutable and you only get the object address by value, so swapping the whole object is not possible because after the method finished, the old object gets reassigned.

Smutje
  • 17,733
  • 4
  • 24
  • 41
1

Only by using some "hacks". You can do this like this:

public static void p1(Integer curInt) {
          Field field = curInt.getClass().getDeclaredField("value"); // Integer stores the real value in private field "value"
          field.setAccessible(true);
          field.set(curInt, 2);

}
walkeros
  • 4,736
  • 4
  • 35
  • 47
  • 3
    It's absolutely inappropriate to use reflection in this case. – Dmitry Ginzburg Oct 03 '14 at 19:35
  • @Dimitry: Why do you think so? It is not beautifull. That's true, but this is what reflection was ment for. – walkeros Oct 03 '14 at 19:37
  • 1
    Reflection should be used, when nothing else can be used. There, `Integer` may be replaced with `AtomicInteger` or OP can pass array (not so good as using just some king of mutable `Integer`, but also possible). – Dmitry Ginzburg Oct 03 '14 at 19:39
  • I totally disagree. AtomicInteger is not an Integer at all. It extends number only to allow it to be used in numeric operations. You can not suggest anyone to use AtomicInteger in place of Integer (consider performance of AtomicInteger for example). – walkeros Oct 03 '14 at 19:45
  • This is absolutely *not* what reflection is meant for. If I ever saw this in a code review, I would reject it *immediately*. Does it work? Yes. Should it be used? Never. – Jon Skeet Oct 03 '14 at 19:52
  • @Jon Who said that you would get this for code review?;) This is not for solving usual cases. This is for solving the problem in some rare cases. – walkeros Oct 03 '14 at 19:53
  • 4
    There are plenty of times that reflection is useful in perfectly reasonable ways. This is *not* one of those times. Heck, it becomes even worse if you're passed in the result of autoboxing a small `int`, as then the mutated (polluted!) object will be used every *other* time you autobox the same value. Code like this should come with a *much* stronger health warning than "only by using some hacks"... – Jon Skeet Oct 03 '14 at 19:56
  • @JonSkeet Thanks, Jon, you're writing exactly what I couldn't word. – Dmitry Ginzburg Oct 03 '14 at 19:58
  • Yes you are right, but using reflection to change a value in any way is a hack. When you use reflection you are putting your code at risk. After all when you access and read value of any private field for example you are risking that this field may no longer be present there when you checkout new version of library/code. Therefore you are not writing anything new :) It's always your decision to use reflection or not. If you use it you need to be aware of consequences. – walkeros Oct 03 '14 at 20:02
  • There are plenty of times when reflection is used without accessing private fields at all. And yes, I agree that you need to be aware of the consequence - so why didn't you warn the OP (who is presumably fairly new to Java) of the risks that this "solution" involves? – Jon Skeet Oct 03 '14 at 20:07
  • "hack" is always a warn. IMHO: people in stackoverflow in many cases creates great answer, but also tend to write more than the person asking the question really would like to hear. – walkeros Oct 03 '14 at 20:12
  • 1
    @walkeros: I would rather write more than an OP *wants* to hear, but tell them everything they *need* to hear than practically invite someone to do something very dangerous, without outlining the risk. – Jon Skeet Oct 03 '14 at 20:33
  • @JonSkeet: Let it be then :) – walkeros Oct 03 '14 at 20:35
  • Interesting thing... giving -1 vote for correct solution. For people who do this instead of understanding why it can be done I would suggest reading all the comments here. If you still want to give -1 I would think if you ever needed to solve more complicated problems in java than just creating service in spring. – walkeros Oct 04 '14 at 05:35
  • Did you verified it? actually it doesn't work at all – DàChún Feb 10 '17 at 10:20
  • @User9527 I have just run it.. works. This code `final Integer integer = new Integer(3); System.out.println(integer); p1(integer); System.out.println(integer);` prints 3 and 2. – walkeros Feb 10 '17 at 10:25
  • sorry, my bad. I was using i = 0; in that case i is int instead of Integer. You are right. – DàChún Feb 10 '17 at 10:29