arynaq
arynaq

Reputation: 6870

References and copying objects, unexpected behavior

I need to know why the following happens, in this code (the last two block) I expect the exact same output yet the local objects (who are mere references to the ones in the list, right?) are in their old state while the list is updated. I have a bug because of a similar copying procedure in my gamecode (tilebased, objects swap positions, so I thought why not just swap their references...)

Example:

package game;

import java.util.ArrayList;


public class Tester {
private String s;
private Foo foo;

public Tester(String s, String f) {
    this.s = s;
    this.foo = new Foo(f);
}

class Foo {
    private String f;

    public Foo(String f) {
        this.f = f;
    }
}

@Override
public String toString() {
    return foo.f + ":" + s;
}
public void swap(Tester other) {
    String tempS = this.s;
    Foo tempFoo = this.foo;

    this.s = other.s;
    this.foo = other.foo;
    other.s = tempS;
    other.foo = tempFoo;

}



public static void main(String[] args) {
    ArrayList<Tester> test = new ArrayList<Tester>();
    test.add(new Tester("First", "1"));
    test.add(new Tester("Second", "2"));

    System.out.println("After initializing list");
    for (Tester t : test) {
        System.out.println(t);
    }

    Tester first = test.get(0);
    Tester second = test.get(1);
    Tester tmp = first;

    first = second;
    second = tmp;

    System.out.println("\nAfter temps");
    System.out.println(first);
    System.out.println(second);

    System.out.println("\nList changed after temps?");
    for (Tester t : test) {
        System.out.println(t);
    }

    System.out.println("\nAfter swap");
    first.swap(second);
    System.out.println(first);
    System.out.println(second);

    System.out.println("\nList after swap");
    for (Tester t : test) {
        System.out.println(t);
    }
}
}

And the output:

After initializing list
1:First
2:Second

After temps
2:Second
1:First

List changed after temps?
1:First
2:Second

After swap
1:First
2:Second

List after swap
2:Second
1:First

I think I was a bit unclear, I always print out first then second (the objects) so "After swap" should look exactly like "List after swap", the list has changed after the swapping of the local objects, the local objects (again, mere references to the ones in the list?) have not.

To the comment in the answer: While my confusion is cleared and my problem solved I was asking whether it is possible to get the actual reference of the list to the object so that when I point it to something else the list will also automagically point to that something else. In the example below Foo a points first to object Foo with attribute A, but this reference it got from list.get(). Now if I point it to new Turtles() the list will still point to Foo with A. enter image description here

I was hoping for a "hard" reference, so that when I point to turtles, the arraylist points to turtles. enter image description here

This would make swapping easier but I am yet unsure of how to implement a list that can do this (if at all possible), this would suit the specific needs of my game very well.

Upvotes: 0

Views: 106

Answers (2)

A4L
A4L

Reputation: 17595

Actually your swap method does not swap the objects themselves but only the values they are containing, the String s is swaped by value, the object foo is swaped by reference.

when you get an element from the list using get(index) you actually get a reference to that object in addition to that internal reference witch the list is holding, so you have there two references pointing to the same object.

to really swap element of a list you should be using the set method of the List with something like that:

Tester tmp = test.get(index);
test.set(index, test.get(index+1));
test.set(index+1, tmp);

this way the elements are swaped in the list so iterating over it will print the result you expect. the swap method you have will be obsolete.

Upvotes: 1

user1131435
user1131435

Reputation:

What you need to bear in mind when working with objects is that the variable which holds the object doesn't actually represent the object. The value of the variable is a pointer in memory to the place where the object exists.

An ArrayList of a certain type of object, by extension, doesn't actually hold objects. It holds object references, or pointers to object locations in memory.

When you say:

Object a = new Object();
Object b = new Object();
a = b;

you're setting a to the value of the pointer to b; in other words, since both a and b point to the same object in memory, changing one changes the other.

Now to answer your question, with this in mind. If you pull two object references out of an ArrayList, and then swap them, you've swapped the references to the objects; however, the references haven't changed location in the ArrayList. This explains the first three outputs.

Once you do an internal swap, however, you've changed the values stored in each object. This means that, though the pointers to the first and second objects are still the same in memory, their internal information has been swapped.

This explains the last two outputs.

(Note, this is also why you have to use System.arraycopy instead of setting int[] a equal to int[] b; if you were to do the latter, then changing a would change b.)

Upvotes: 3

Related Questions