1
public void method (AmazingObject obj) {

    HashMap<Integer, AmazingObject> hashmap = new HashMap<>();

    for (int i = 0; i < 5; i++) {
        obj = new AmazingObject();
        hashmap.put(i, obj);
    }

    for (int i = 0; i < 5; i++) {
        System.out.println(hashmap.get(i).toString());
    } 

}

I wrote this code out and see that the array contains completely different objects for every element. If I understand this properly:

1) The method accepts a reference copy of an AmazingObject instance.

2) I assign a new address to that reference type by using the new keyword.

3) Another reference copy containing my new address is thrown into the Hashmap.

Therefore, none of the previous values are overwritten. Is the reason for this behavior that Java is pass by reference copy and not pass by reference? I would have expected every element in the array to point to the exact same object at the end (i.e. the last assigned object).

Mena
  • 47,782
  • 11
  • 87
  • 106
Mmm Donuts
  • 9,551
  • 6
  • 27
  • 49
  • I read that question, that's where I got my information from. Im just wondering if this is the case. Is it correct to expect totally different objects across the HashMap? – Mmm Donuts Nov 06 '17 at 14:58
  • you keep on reassigning obj to new objects and putting them into a map so you end up with a map that has 5 different objects. what is your question? – isaace Nov 06 '17 at 15:02
  • this might explain what you're seeing https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value/12429953#12429953 – codebrane Nov 06 '17 at 15:02

3 Answers3

1

If I understand you correctly you would expect that the following code:

HashMap<Integer, MyObject> hashmap ...    // Line 0
MyObject foo = new MyObject();            // Line 1
hashmap.put(1, foo);                      // Line 2
foo = new MyObject();                     // Line 3
hashmap.put(2, foo);                      // Line 4

will result in a hashmap where both values are the same.


Lets look at this example step by step:

  1. After Line 1
    • the stack has 2 entries/pointers (hashmap, foo) and they are pointing to memory objects in
    • the heap (1 HashMap and 1 instance of MyObject).
  2. After Line 2
    • the stack is unchanged.
    • the heap HashMap memory object now contains an entry that maps 1 to a pointer that points to the instance of MyObject
  3. After Line 3
    • the stack pointer foo is now pointing to a different memory location on the heap (the newly created instance of MyObject)
    • the heap now holds a HashMap and two instances of MyObject
  4. After Line 4
    • the stack is unchanged.
    • the heap HashMap memory object now contains 2 entries (1 -> pointer to the first MyObject instance | 2 -> pointer to the second MyObject instance)

I hope you understand what i mean but important is: A variable/parameter is NOT the object itself. Its just a container that holds a pointer to the memory location.

Therefore if you give that pointer to the memory location to anyone else (in your case to a HashMap) then that other location won't know if the variable is changed later!

ParkerHalo
  • 4,341
  • 9
  • 29
  • 51
  • Ah, so the HashMap is accepting the memory location itself - NOT the variable to it. That would explain the behavior. So the parameter that enters the method is a variable containing a memory address. However, the HashMap actually stores the memory address value, NOT the reference to it. Is that correct? – Mmm Donuts Nov 06 '17 at 15:36
  • Yes, thats it! :) – ParkerHalo Nov 06 '17 at 16:04
0

You can have the same reference in all options, but you can't use the new keyword, so instead:

for (int i = 0; i < 5; i++) {
    obj = new AmazingObject();
    hashmap.put(i, obj);
}

Do:

obj = new AmazingObject();
for (int i = 0; i < 5; i++) {
    hashmap.put(i, obj);
}
Marcos Vasconcelos
  • 18,136
  • 30
  • 106
  • 167
  • I get that! My question pertains to the `why` more so than the implementation. I should probably be more clear. – Mmm Donuts Nov 06 '17 at 15:16
  • Well, think that, every new keyword a reference is created into memory, assignments only "points" to instances. (No pointer logics allowed) – Marcos Vasconcelos Nov 06 '17 at 15:21
-1

The input parameter is irrelevant since you keep reassigning it in your first for loop, so yes you end up with 5 new objects that are stored in the map. This is one reason why I always make input parameters final - it prevents their reassignment which can cause confusion like this example

V3V
  • 107
  • 5
  • But isn't the same variable being overwritten again and again? I may be thinking of pointers a little too much here. So the value that gets passed into the HashMap is a reference copy? I keep imagining that variable pointing to the same memory location and that location being overwritten. That's where my confusion is coming from. – Mmm Donuts Nov 06 '17 at 15:05
  • @Kris you need to understand that once you put the instance in the map it stays there even if the variable is reassigned to a different instance. In fact, you can even skip "obj = new AmazingObject();" and just write hashmap.put(i, new AmazingObject();" and you'll get the same results. – isaace Nov 06 '17 at 15:07
  • I understand that much. Im just wondering what's happening here at a lower level. When you call 'new', you're getting a brand new memory location - which you then store in your variable. If I keep changing it, it will keep getting overwritten. My question is, why does the HashMap 'freeze' those address values? – Mmm Donuts Nov 06 '17 at 15:10
  • Try to draw a sketch (heap, stack) for your example and you'll understand it pretty soon... Try to include where and what variables, pointers and memory-objects are in java! – ParkerHalo Nov 06 '17 at 15:14
  • Do they in any way differ from C++? – Mmm Donuts Nov 06 '17 at 15:15