为什么Java枚举不可克隆?

Chr*_*fer 7 java enums clone

现在改变这个问题为时已晚,但更准确的是问"为什么克隆()不允许单身人士?".一个copy()方法会更方便.


是否有任何理由不能克隆Java中的枚举?

手册说明了这一点

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

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

有人可能会说

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

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

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

Mig*_*ing 9

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

严格来说,如果要克隆某些内容强制执行x.clone() == x,则唯一可能是克隆结果的对象x本身就是:

def clone() {
  return this;
}
Run Code Online (Sandbox Code Playgroud)

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


如果你正在设计一些东西并且是基于clone()差异化的,那么你做错了恕我直言......


Dan*_*yer 7

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

Javadoc说:

按照惯例,此方法返回的对象应独立于此对象(正在克隆).

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

编辑:回应以下评论:

这正是我批评的.为什么不返回相同的实例,如果不能有不同的实例?

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

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

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

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

您没有真正解释为什么要将枚举视为Cloneable本身不可复制的内容.想要一个不遵守公认惯例的克隆方法似乎是解决一些更基本问题的方法.


gus*_*afc 6

但对于单身人士而言,我希望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?
Run Code Online (Sandbox Code Playgroud)

(当然,因为clone()只提供浅拷贝,所以即使正确实现它也可能导致上述代码出错.)

另一方面,我可以同意克隆操作仅return this适用于不可变对象是有意义的,并且枚举确实应该是不可变的.现在,当签订合同时clone(),他们显然没有考虑不可变因素,或者他们不希望语言不支持的概念的特殊情况(即不可变类型).

所以,clone()就是这样,你不能很好地去改变的东西,一直围绕自从Java 1.0.我非常肯定在那里的某个地方,有些代码完全依赖于clone()返回一个新的,独特的对象,可能作为一个IdentityHashMap或某个东西的关键.