Reputation: 59385
I'm having some trouble with making list of objects based on a condition on an enum
. It seems that after I have completed the list, every item in the list is equivalent to the last item.
It's the classic case of different references pointing to the same object, but I don't know how to avoid it:
I've pared things down as much as I can while maintaining readability:
public class Foo {
Digit[] array = new Digit[2];
ArrayList<Foo> foozlets;
Foo() {
array[0] = Digit.ZERO;
foozlets = new ArrayList<Foo>();
}
Foo(Foo old, Digit num) {
this.array = old.array; \\This line is a problem, what should it say?
array[1] = num;
}
public static void main(String[] args) {
Foo f = new Foo();
System.out.println("Initial Foo:");
System.out.println(f);
f.listFoozlets();
}
void listFoozlets() {
for (Digit k : Digit.values()) {
if (k == Digit.TWO || k == Digit.FIVE) {
foozlets.add(new Foo(this, k));
System.out.println("** Foozlet being added **");
Foo foo = new Foo(this, k);
System.out.println(foo);
}
}
System.out.println("** List of Foozlets **");
for (Foo foo : foozlets) {
System.out.println(foo);
}
}
public String toString() {
return array[0].toString() + " " + array[1].toString();
}
}
enum Digit { ZERO, ONE, TWO, THREE, FOUR, FIVE }
Here is the output:
Initial Foo:
ZERO NULL
** Foozlet being added **
ZERO TWO
** Foozlet being added **
ZERO FIVE
** List of Foozlets **
ZERO FIVE
ZERO FIVE
If someone can explain why the first instance of Foo
on the list changes, and how I can make a list that doesn't change, I'd be grateful.
EDIT: Ok, I see where the problem is now. In the real, much larger program, I have a much larger array, and I want to keep the old information when I create a new Foo for the list. I've changed the code to reflect that there is additional information that I want to maintain. How do I accomplish this?
EDIT 2021: Wandered upon this, one of my first SO questions, twelve years later. If this helped you, I'm glad for that. If you are wondering what in the world I was trying to do, the answer is "I have no idea."
Upvotes: 2
Views: 525
Reputation: 29700
Instead of
Foo(Foo old, Digit num) {
this.array = old.array;
array[0] = num;
}
simply do
Foo(Foo old, Digit num) {
array[0] = num;
}
if you really need the array at all... (best would be to use a simple Digit as suggested in another reply)
Upvotes: 0
Reputation: 91911
The problem appears to be in this line:
this.array = old.array;
You are sharing array references, so every Foo shares the same array, so they all have the same value at array[0].
To fix this, try:
this.array = old.array.clone();
Upvotes: 2
Reputation: 14851
The object reference in this case is the array. The constructor of foo is where you're having the issue, specifically:
Foo(Foo old, Digit num) {
this.array = old.array; // reference the old array
array[0] = num; // set the first element of the array (for this AND the old array) to num
}
You need to copy the array to a new array in the constructor of foo.
Upvotes: 1
Reputation: 361849
In your second constructor:
Foo(Foo old, Digit num) {
this.array = old.array;
array[0] = num;
}
You are re-using the list from old
. You want to create a copy of that list rather than using the same list. You can do that by changing the assignment to:
Foo(Foo old, Digit num) {
this.array = new ArrayList<Foo>(old.array);
array[0] = num;
}
Upvotes: 3
Reputation: 1502176
This bit is the culprit:
Foo(Foo old, Digit num) {
this.array = old.array;
array[0] = num;
}
You're copying a reference to the old Foo's array, and then changing the value in that array.
Why do you even have an array of size 1 instead of just a Digit
? If you really want the array, you possibly want to clone it instead of just copying the reference, but we can't really tell what the intention is.
Here's a shorter example:
enum Digit { ZERO, ONE, TWO, THREE, FOUR, FIVE }
public class Foo {
Digit[] array = new Digit[1];
Foo() {
array[0] = Digit.ZERO;
}
Foo(Foo old, Digit num) {
this.array = old.array;
array[0] = num;
}
public String toString() {
return array[0].toString();
}
public static void main(String[] args) {
Foo f = new Foo();
System.out.println(f);
Foo other = new Foo(f, Digit.ONE);
System.out.println(f);
}
}
Upvotes: 7