Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are these Java enums changing values?

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."

like image 620
Eric Wilson Avatar asked Feb 12 '26 16:02

Eric Wilson


1 Answers

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);
  }
}
like image 139
Jon Skeet Avatar answered Feb 15 '26 06:02

Jon Skeet



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!