How can I pass an Integer class correctly by reference?

110,695

Solution 1

There are two problems:

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

  1. Use org.apache.commons.lang.mutable.MutableInt from Apache Commons library.
  2. 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 :-)

Share:
110,695
sixtyfootersdude
Author by

sixtyfootersdude

Updated on August 29, 2020

Comments

  • sixtyfootersdude
    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
    bwawok almost 14 years
    It'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
    sixtyfootersdude almost 14 years
    huh, ok that is interesting. Thanks for the auto-boxing term. Immutable also seems pretty key. Have a good weekend!
  • BalusC
    BalusC almost 14 years
    Strictly speaking, for references it's "pass reference by value" and for primitives it's just "pass by value".
  • bwawok
    bwawok almost 14 years
    Ya 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
    Rodislav Moldovan over 10 years
    well, a duplicate of reference is sent into the function
  • Rahul Jain
    Rahul Jain over 8 years
    Why Integer is made immutable?
  • Markos
    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
    Rahul Jain over 8 years
    What do you mean by consistent. int can be changed but not Integer, This is kinda downside of the wrapper class.
  • Markos
    Markos over 8 years
    @RahulJain int is a primitive type. Primitive types are immutable. I suspect you confuse immutability with the final keyword - they are different things. You can change the reference of Integer variable (the same as the value of int variable). They are pretty much consistent.
  • Sreekanth Karumanaghat
    Sreekanth Karumanaghat over 7 years
    How is duplicate of reference sent to function different from sending reference to function? Is there any significant difference?
  • A.B.
    A.B. about 7 years
    BalusC 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
    krizajb over 5 years
    What about performance, is it intact? Obviously if AtomicInteger is needed only to pass by reference it isn't needed for thread safety.
  • PlsWork
    PlsWork about 4 years
    Performance seems to be the same as Integer (assuming you are just using .set(), .get() and are not using any of the thread-safe operations).