为什么Java枚举不可复制?

时间:2009-11-26 12:49:06

标签: java enums clone

现在改变这个问题为时已晚,但更精确的是要问“为什么clone()不允许单身人士?”。 copy()方法会更方便。


有没有理由不能克隆Java中的枚举?

手册说明

  

这保证了枚举永远不会被克隆,这是保持其“单身”状态所必需的。

但是返回实例本身也会保留其状态,并且我能够以与其他可克隆对象相同的方式处理关联的枚举。

有人可能会争辩说

  

[clone]的一般意图是,对于任何对象x,表达式为:    x.clone() != x将是真的,[...]

但对于单身人士而言,我希望x.clone() == x成立。如果返回实例本身,则单例模式对于引用对象是透明的。

那么,当指定clone()时,为什么不允许克隆枚举或者忘记考虑单身人士和不可变因素?

6 个答案:

答案 0 :(得分:8)

如果x.clone() == x,克隆单身人士的目的是什么?你不能马上使用x

严格地说,如果你想要克隆一些强制执行x.clone() == x,那么唯一可能是克隆结果的对象就是x本身:

def clone() {
  return this;
}

这可能会误导......


如果您正在设计某些内容并且基于clone()进行区分,那么您做错了恕我直言......

答案 1 :(得分:6)

如果你的clone方法返回this实例而不是一个不同的对象,那么它不是克隆,是吗?

The Javadoc说:

  

按照惯例,返回的对象   这种方法应该是独立的   这个对象(正在被克隆)。

不应该克隆枚举,因为应该只有每个值的一个实例。

编辑:回复以下评论:

  

这正是我的批评。为什么   不返回相同的实例,如果有的话   不可能是一个不同的?

因为它没有意义。如果它是同一个对象,那么它不是克隆。 Javadocs还说:

  

一般意图是,任何   对象x,表达式:

x.clone() != x
将是真的,那就是   表达式:
x.clone().getClass() == x.getClass()
将是真的,但这些   不是绝对的要求。

因此意图是clone()方法返回一个不同的对象。不幸的是,它说这不是一个绝对的要求,这使你的建议有效,但我仍然认为这是不明智的,因为拥有一个返回this的克隆方法是没有用的。如果你正在做一些可疑的事情,比如你的枚举常量中有可变状态或者同步它们,它甚至可能会引起问题。这些代码的行为会有所不同,具体取决于克隆方法是否进行了适当的克隆或仅返回this

您并没有真正解释为什么要将枚举视为Cloneable,因为它们本身就是不可复制的。想要一个不遵守公认惯例的克隆方法似乎是解决你的方法中一些更基本问题的黑客。

答案 2 :(得分:5)

  

但对于单身人士而言,我希望x.clone() == x成为现实。

可能想要,但我认为下面的代码会破坏是很奇怪的:

interface Foo extends Cloneable { public int getX(); public void setX(int x);  }
enum FooSingleton implements Foo { 
    INSTANCE; 
    private int x;
    public int getX(){ return x; }
    public void setX(int x){ this.x = x; }
}
class FooClass implements Foo { 
    private int x;
    public int getX(){ return x; }
    public void setX(int x){ this.x = x; }
}

boolean omg(Foo f){
    Foo c = f.clone();
    c.setX(c.getX() + 1);
    return c.getX() != f.getX();   
}
assert omg(new FooClass());        // OK
assert omg(FooSingleton.INSTANCE); // WTF?

(当然,由于clone()只提供浅拷贝,即使正确实现它也可能导致上述代码出错。)

另一方面,我可以同意,对于不可变对象克隆操作仅仅return this是有意义的,并且枚举确实应该是不可变的。现在,当编写clone()的合同时,他们显然没有考虑不可变,或者他们不想要一个特殊情况,因为这个概念不受语言支持(即不可变类型)。 p>

所以,clone()就是这样,你不可能去改变自Java 1.0以来一直存在的东西。我很确定在那里的某个地方,有些代码完全依赖于clone()返回一个新的,不同的对象,可能作为IdentityHashMap或其他东西的关键。

答案 3 :(得分:1)

我猜他们不希望在指定clone()时将单身人士视为一种特殊情况。这会使规范变得复杂。因此,现在图书馆开发人员必须将它们视为特殊情况,但对于我们其他人来说,我们可以信任x.clone() != x很好。

答案 4 :(得分:1)

你自己对问题的回答是最好的。一般来说,人们期望clone()回馈不同的对象。 Cloneable本身的语义更有意义。 (“这个对象是可以克隆的......哦,我必须能够制作副本。”)我无法想到一个重要的情况,但那是Cloneable的预期语义。

我认为即使他们考虑单身人士,他们也不会改变它。毕竟,程序员有责任通过有选择地添加(并可能覆盖)Cloneable接口来决定可克隆的内容和不可克服的内容,并且大多数程序员不会添加Cloneable接口单身人士。

答案 5 :(得分:0)

  

但对于单身人士而言,我希望x.clone() == x成为现实。

不,那不会是克隆。所以,对于单身人士,你想要这个:

public Object clone() throws CloneNotSupportedException {
  throw new CloneNotSupportedException(); 
}