1

What I Have: A static ArrayList which stores Integers. I add an Integer via reference to it and then I change the value but the value is not updated.

import java.util.ArrayList;

public class Main {

    public static final ArrayList<Integer> integers = new ArrayList<>();
    public Integer integer;

    void addInteger(Integer i){
        integers.add(i);
    }

    public static void main(String[] args) {

        Main main = new Main();
        main.integer = 3;

        integers.add(main.integer);

        main.integer = 4;

        System.out.println(integers.get(0));

    }
}

Output: 3

Question: Why is the output not 4 ?

Further Question based on follow ups: What is really stored within the ArrayList ?

EDIT BASED ON THE ACCTPTED ANSWER:

Since integer is an Integer (and not an int) the 3 is autoboxed. The ArrayList stores actually Integer.valueOf(3).

SklogW
  • 839
  • 9
  • 22
  • 1
    You added 3 to the list, not 4. That is why 3 is the expected output. If you would add main.integer again to the list, after assigning main.integer = 4, the output will be 4. – Max May 20 '15 at 20:24
  • I added main.integer to it only stores the value at the time it was added ? – SklogW May 20 '15 at 20:26
  • 2
    When you do `integers.add(main.integer);` you pass *the value* contained in `main.integer` to the `add` method. If you change the content of that variable after you have called `add` it doesn't affect the list. – aioobe May 20 '15 at 20:26
  • 1
    The list has the copied value of main.integer at the time you added it. So changing it afterwards will not change the list containing the integers. You would have to modify the item in the list. – Max May 20 '15 at 20:27
  • possible duplicate of [java Integer reference](http://stackoverflow.com/questions/6562337/java-integer-reference) – zubergu May 20 '15 at 20:27

3 Answers3

3

When executing main.integer = 4 you're reassigning the value of main.integer, but the old reference was already added to the List<Integer>. Here's what happens in the code:

//commented this line
//main.integer = 3;
//this line below is what really happens
main.integer = Integer.valueOf(3);
integers.add(main.integer);
//main.integer = 4;
main.integer = Integer.valueOf(4);
Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332
  • I am just trying to wrap my head around it. When I add main.integer Java doesn't care where it comes from but only what's in there ? – SklogW May 20 '15 at 20:29
  • 2
    @LuiggiMendoza This behavior does not really have to do anything with the fact that `Integer` is immutable, does it? It should behave exactly the same way with a mutable class like `java.util.Date`, shouldn't it? – TimoStaudinger May 20 '15 at 20:30
  • @TimoSta fixed the wording. The explanation was at the bottom. Removed that part of immutability. – Luiggi Mendoza May 20 '15 at 20:38
  • @SklogW first, you add the value of the reference stored in `main.integer` into your `List`. Then, you reassign a new reference to the variable `main.integer`. The old reference was already added into the `List`. Java is pass by value, not pass by reference, so if you change the value of the reference of a variable, this won't be reflected in the other variables. Don't confuse value of the reference with state of the reference. – Luiggi Mendoza May 20 '15 at 20:45
3

Here's what happens:

  • You create a reference to 3 (and store that reference in main.integer).
  • This reference is then stored in the list (by integers.add(main.integer)). The reference to 3 is passed by value, so the reference is copied into the list.
  • You then update main.integer to contain a reference to 4. This does not affect what is stored in the list.

Compare this with the following snippet:

public AtomicInteger integer;

Main main = new Main();
main.integer = new AtomicInteger(3);  // Reference to a mutable object

integers.add(main.integer);           // Add reference to list

main.integer.set(4);                  // Change mutable object

System.out.println(integers.get(0));  // Prints 4
aioobe
  • 413,195
  • 112
  • 811
  • 826
  • So does it pass the primitive which is wrapped within the Integer ? – SklogW May 20 '15 at 20:34
  • Very good follow up question. The answer is *no*. Primitives does not have to do with it. Keep in mind that an `Integer` variable contains a *reference* to an object on the heap. An `Integer` does *not* contain the value `3`. – aioobe May 20 '15 at 20:36
  • I like the bulletlist, explaining what is happening. However I think the code snippet makes things more complicated. – Max May 20 '15 at 20:36
  • Then where does the reference come from which contains the number 3 when it's not a primitive ? Sorry for the noob question but I'd really like to know what is going on here since I think this is kind of important. – SklogW May 20 '15 at 20:38
  • Ah, another good question. Since you assign `3` to an `Integer` (and not to an `int`) the value will be [*auto boxed*](http://stackoverflow.com/questions/18850930/java-integer-auto-auto-boxing) into an `Integer`. In other words, the literal `3` will basically be compiled into `Integer.valueOf(3)` and that's where the reference comes into play. – aioobe May 20 '15 at 20:40
  • 1
    ...and Integer.valueOf(3) is what's actually stored within the ArrayList ? – SklogW May 20 '15 at 20:44
  • @Max, I think the snippet is important because that snippet works the way OP thought the original snippet should have worked (but highlights the difference). – aioobe May 20 '15 at 20:44
0

From your current code you only assign the first element of your list a value (3). If you are expecting to output 4 you need to do 2 things. First make sure you add a new value to your ArrayList. Add another integers.add(main.integer); after you change the value of main.integer. After you add another element to your ArrayList remember to index the new correct element. ie: System.out.println(integers.get(1));