1

I am quite new to programming in Java, but I have some experience in c/c++, I am noticing some unwanted behaviour in some of my code, and I am just wondering how to fix it.

This is what I have:

List<State> list = new ArrayList<State>();
State cur = new State();
cur.x = 1;
cur.y = 1;
list.add(cur);
cur.x = 2;
cur.y = 3;
list.add(cur);
cur.x = 3;
cur.y = 4;
list.add(cur);
for (State i : list)
    System.out.println(i.x + " " + i.y);


class State
{
    public int x = 0;
    public int y = 0;
}

This gives me an output of: 3 4 3 4 3 4

Where as I want the output to be: 1 1 2 3 3 4

How do I fix this? Thanks, paintstripper

4 Answers 4

2

In C++ you may be expecting this List.add() function to use a copy constructor, but in Java all objects (i.e. not primitive types) are essentially references. This means that after you add cur into the list you're adding a reference to it there. You're then modifying the values below through the cur reference so that they are all 3 and 4.

To fix your problem you should use different State objects and add them separately.

Edit: Just to add a little bit more information here, Java always by value. When you pass an object into a function however, since that object is essentially a reference, the reference is passed by value. This means that while you could modify the original object inside a function, if you assign new things to the reference inside that function (such as swapping two objects with a temp value) it won't work.

Sign up to request clarification or add additional context in comments.

1 Comment

I don't think it helps to say "all objects are references". There's still a difference between an object and a reference - but all expressions are either references or primitive values.
2

You have one and only one object, but you add 3 different references to it to the list and change it's state (x and y) meanwhile. So at the end its x is 3 and its y is 4.

You probably want to add different objects. So:

List<State> list = new ArrayList<State>();
State cur = new State();
cur.x = 1;
cur.y = 1;
list.add(cur);
cur = new State();
cur.x = 2;
cur.y = 3;
list.add(cur);
cur = new State();
cur.x = 3;
cur.y = 4;
list.add(cur);
for (State i : list)
    System.out.println(i.x + " " + i.y);


class State
{
    public int x = 0;
    public int y = 0;
}

1 Comment

He's not adding the same object to the list 3 times. He's adding three references to the same object to the list 3 times.
1

The problem you have is that you're mutating a single object. It's better to avoid publicly mutable member variables. If you write the State class as below you would not have been able to make the programming error.

List<State> list = new ArrayList<State>();
State cur = new State(1,1);
list.add(cur);
cur = new State(2,3);
list.add(cur);
cur = new State(3,4);
list.add(cur);
for (State i : list)
    System.out.println(i.x + " " + i.y);


class State
{
    public final int x;
    public final int y;

    public State(int x, int y) 
    {
        this.x = x;
        this.y = y;
    }

}

Note the final keyword on the x and y members, this means they cannot be assigned to after construction.

1 Comment

This is what I needed. I understand it now and how to avoid it. Thanks!
1

Quite simple, do a cur = new State() after each list.add() so that you get a new instance of State in 'cur'. What you are doing instead is adding the same instance to list, this is no different from C++ if you used pointer or reference of State in cur.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.