为什么这些Java枚举会改变价值?

时间:2009-07-23 13:24:48

标签: java enums reference

我在根据enum上的条件制作对象列表时遇到了一些麻烦。似乎在我完成列表后,列表中的每个项目都等同于最后一项。

这是指向同一个对象的不同引用的经典案例,但我不知道如何避免它:

在保持可读性的同时,我尽可能地减少了事情:

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 }

这是输出:

Initial Foo:
ZERO NULL
** Foozlet being added **
ZERO TWO
** Foozlet being added **
ZERO FIVE
** List of Foozlets **
ZERO FIVE
ZERO FIVE

如果有人能够解释为什么列表中Foo的第一个实例发生了变化,以及如何制作一个不会改变的列表,我将不胜感激。

编辑:好的,我现在看到问题所在。在真正的,更大的程序中,我有一个更大的数组,并且我想在为列表创建新的Foo时保留旧信息。我已经更改了代码以反映我想要维护的其他信息。我该如何做到这一点?

5 个答案:

答案 0 :(得分:6)

这一点是罪魁祸首:

Foo(Foo old, Digit num) {
  this.array = old.array;
  array[0] = num;
}

您正在将引用复制到旧的Foo数组,然后更改该数组中的值。

为什么你甚至有一个大小为1而不只是Digit的数组?如果你真的想要这个数组,你可能想要克隆它而不是仅仅复制引用,但是我们无法真正说明它是什么意思。

这是一个较短的例子:

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);
  }
}

答案 1 :(得分:2)

在你的第二个构造函数中:

Foo(Foo old, Digit num) {
  this.array = old.array;
  array[0] = num;
}

您正在重复使用old中的列表。您想要创建该列表的副本,而不是使用相同的列表。您可以通过将分配更改为:

来实现
Foo(Foo old, Digit num) {
  this.array = new ArrayList<Foo>(old.array);
  array[0] = num;
}

答案 2 :(得分:2)

问题似乎出在这一行:

    this.array = old.array;

您正在共享数组引用,因此每个Foo共享相同的数组,因此它们在数组[0]中具有相同的值。

要解决此问题,请尝试:

  this.array = old.array.clone();

答案 3 :(得分:1)

在这种情况下,对象引用是数组。 foo的构造函数是你遇到问题的地方,特别是:

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
}

您需要将数组复制到foo的构造函数中的新数组。

答案 4 :(得分:0)

而不是

Foo(Foo old, Digit num) {
  this.array = old.array;
  array[0] = num;

}

简单地做

Foo(Foo old, Digit num) {
  array[0] = num;

}

如果你真的需要阵列...... (最好是使用另一个回复中建议的简单数字)