How can I pass an Integer class correctly by reference?
Solution 1
There are two problems:
- Integer is pass by value, not by reference. Changing the reference inside a method won't be reflected into the passed-in reference in the calling method.
- Integer is immutable. There's no such method like
Integer#set(i)
. You could otherwise just make use of it.
To get it to work, you need to reassign the return value of the inc()
method.
integer = inc(integer);
To learn a bit more about passing by value, here's another example:
public static void main(String... args) {
String[] strings = new String[] { "foo", "bar" };
changeReference(strings);
System.out.println(Arrays.toString(strings)); // still [foo, bar]
changeValue(strings);
System.out.println(Arrays.toString(strings)); // [foo, foo]
}
public static void changeReference(String[] strings) {
strings = new String[] { "foo", "foo" };
}
public static void changeValue(String[] strings) {
strings[1] = "foo";
}
Solution 2
The Integer is immutable. You can wrap int in your custom wrapper class.
class WrapInt{
int value;
}
WrapInt theInt = new WrapInt();
inc(theInt);
System.out.println("main: "+theInt.value);
Solution 3
Good answers above explaining the actual question from the OP.
If anyone needs to pass around a number that needs to be globally updated, use the AtomicInteger(
) instead of creating the various wrapper classes suggested or relying on 3rd party libs.
The AtomicInteger(
) is of course mostly used for thread safe access but if the performance hit is no issue, why not use this built-in class. The added bonus is of course the obvious thread safety.
import java.util.concurrent.atomic.AtomicInteger
Solution 4
There are 2 ways to pass by reference
- Use org.apache.commons.lang.mutable.MutableInt from Apache Commons library.
- Create custom class as shown below
Here's a sample code to do it:
public class Test {
public static void main(String args[]) {
Integer a = new Integer(1);
Integer b = a;
Test.modify(a);
System.out.println(a);
System.out.println(b);
IntegerObj ao = new IntegerObj(1);
IntegerObj bo = ao;
Test.modify(ao);
System.out.println(ao.value);
System.out.println(bo.value);
}
static void modify(Integer x) {
x=7;
}
static void modify(IntegerObj x) {
x.value=7;
}
}
class IntegerObj {
int value;
IntegerObj(int val) {
this.value = val;
}
}
Output:
1
1
7
7
Solution 5
What you are seeing here is not an overloaded +
oparator, but autoboxing behaviour. The Integer
class is immutable and your code:
Integer i = 0;
i = i + 1;
is seen by the compiler (after the autoboxing) as:
Integer i = Integer.valueOf(0);
i = Integer.valueOf(i.intValue() + 1);
so you are correct in your conclusion that the Integer
instance is changed, but not sneakily - it is consistent with the Java language definition :-)
sixtyfootersdude
Updated on August 29, 2020Comments
-
sixtyfootersdude over 3 years
I am hoping that someone can clarify what is happening here for me. I dug around in the integer class for a bit but because integer is overriding the
+
operator I could not figure out what was going wrong. My problem is with this line:Integer i = 0; i = i + 1; // ← I think that this is somehow creating a new object!
Here is my reasoning: I know that java is pass by value (or pass by value of reference), so I think that in the following example the integer object should be incremented each time.
public class PassByReference { public static Integer inc(Integer i) { i = i+1; // I think that this must be **sneakally** creating a new integer... System.out.println("Inc: "+i); return i; } public static void main(String[] args) { Integer integer = new Integer(0); for (int i =0; i<10; i++){ inc(integer); System.out.println("main: "+integer); } } }
This is my expected output:
Inc: 1 main: 1 Inc: 2 main: 2 Inc: 3 main: 3 Inc: 4 main: 4 Inc: 5 main: 5 Inc: 6 main: 6 ...
This is the actual output.
Inc: 1 main: 0 Inc: 1 main: 0 Inc: 1 main: 0 ...
Why is it behaving like this?
-
bwawok almost 14 yearsIt's not really pass by value. It's pass by value of the reference.... as the only thing being passed for objects is a memory address.
-
sixtyfootersdude almost 14 yearshuh, ok that is interesting. Thanks for the auto-boxing term. Immutable also seems pretty key. Have a good weekend!
-
BalusC almost 14 yearsStrictly speaking, for references it's "pass reference by value" and for primitives it's just "pass by value".
-
bwawok almost 14 yearsYa look up autoboxing. Back in Java 1.4 you could only add ints with ints, or Integers with Integers. The fact you can do in any way now can be a little difficult to conceptualize just looking at code.
-
Rodislav Moldovan over 10 yearswell, a duplicate of reference is sent into the function
-
Rahul Jain over 8 yearsWhy Integer is made immutable?
-
Markos over 8 years@RahulJain Not sure, I suspect it is to be consistent with the actual value type (
int
), so they both have the same semantics. -
Rahul Jain over 8 yearsWhat do you mean by consistent. int can be changed but not Integer, This is kinda downside of the wrapper class.
-
Markos over 8 years@RahulJain
int
is aprimitive
type. Primitive types are immutable. I suspect you confuse immutability with thefinal
keyword - they are different things. You can change the reference ofInteger
variable (the same as the value ofint
variable). They are pretty much consistent. -
Sreekanth Karumanaghat over 7 yearsHow is duplicate of reference sent to function different from sending reference to function? Is there any significant difference?
-
A.B. about 7 yearsBalusC has nailed it, but here is simple explanation. Java sends in a copy-of-reference which is created on a function's stack.The line strings = new String[]{"foo", "foo"}; modifies the copy-of-reference created on changeReference(String[]) local stack. Calling function main() is aware of reference created on it's own stack (not that of created on changeReference() stack).
-
krizajb over 5 yearsWhat about performance, is it intact? Obviously if
AtomicInteger
is needed only to pass by reference it isn't needed for thread safety. -
PlsWork about 4 yearsPerformance seems to be the same as Integer (assuming you are just using .set(), .get() and are not using any of the thread-safe operations).