为什么 Java 枚举不可克隆?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1803503/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 18:03:02  来源:igfitidea点击:

Why are Java enums not clonable?

javaenumsclone

提问by Christian Strempfer

It's too late to change the question, but more precise would have been to ask "Why does clone() not allow singletons?". A copy()method would be more convenient.

现在改变问题为时已晚,但更准确的问题是“为什么 clone() 不允许单例?”。一种copy()方法会更方便。



Is there any reason why enums in Java cannot be cloned?

有什么原因不能克隆 Java 中的枚举吗?

The manual states that

该手册指出

This guarantees that enums are never cloned, which is necessary to preserve their "singleton" status.

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

But returning the instance itself would also preserve its status, and I would be able to handle associated enums the same way as other clonable objects.

但是返回实例本身也会保留其状态,并且我将能够像处理其他可克隆对象一样处理关联的枚举。

One may argue that

有人可能会争辩说

The general intent [of clone()] is that, for any object x, the expression: x.clone() != xwill be true, [...]

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

But for singletons on the contrary I want x.clone() == xto be true. If the instance itself would be returned, then the singleton pattern would be transparent to referencing objects.

但对于单身人士相反,我想x.clone() == x是真的。如果实例本身将被返回,那么单例模式对于引用对象将是透明的。

So why are enums not allowed to be cloned or did they forget to think about singletons and immutables, when clone()was specified?

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

采纳答案by gustafc

But for singletons on the contrary I want x.clone() == xto be true.

但对于单身人士相反,我想x.clone() == x是真的。

Youmay want to, but I think it's weird that the following code would break:

可能想要,但我认为以下代码会中断很奇怪:

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?

(Of course, since clone()only gives shallow copies, even a correct implementation of it may cause errors in the above code.)

(当然,由于clone()只给出了浅拷贝,即使是正确的实现也可能导致上面代码出错。)

On the other hand, I can sort of agree that it would make sense for cloning operations to just return thisfor immutable objects, and enums really should be immutable. Now, when the contract for clone()was written, they apparently didn't think about immutables, or they didn't want a special case for a concept that's not supported by the language (i.e., immutable types).

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

And so, clone()is what it is, and you can't very well go and change something that's been around since Java 1.0. I'm quite certain that somewhere out there, there is code that totally relies on clone()returning a new, distinct object, perhaps as a key for an IdentityHashMapor something.

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

回答by Miguel Ping

What's the purpose of cloning a singleton, if x.clone() == x? Can't you just use xstraight away.

克隆单身人士的目的是什么,如果x.clone() == x?不能直接用吗x

Strictly speaking, if you want to clone something andenforce x.clone() == x, the only object that can be the result of the clone is xitself:

严格来说,如果你想克隆一些东西强制执行x.clone() == x,唯一可以作为克隆结果的对象是x它自己:

def clone() {
  return this;
}

Which can be misleading...

这可能会产生误导......



If you are designing something and are based on clone()for differentiation, you are doing it wrong IMHO...

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

回答by Dan Dyer

If your clone method returns thisinstance rather than a distinct object, then it's not a clone, is it?

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

The Javadocsays:

Javadoc说:

By convention, the object returned by this method should be independent of this object (which is being cloned).

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

Enums are not supposed to be cloned because there is supposed to only ever be one instance of each value.

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

EDIT:In response to the following comment:

编辑:回应以下评论:

That's exactly what I criticize. Why not return the same instance, if there cannot be a different one?

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

Because it doesn't really make sense. If it's the same object then it's not a clone. The Javadocs also say:

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

The general intent is that, for any object x, the expression:

x.clone() != x
will be true, and that the expression:
x.clone().getClass() == x.getClass()
will be true, but these are not absolute requirements.

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

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

So the intent is for the clone()method to return a distinct object. Unfortunately it says that it's not an absolute requirement, which makes your suggestion valid, but I still think it's not sensible because it's not useful to have a clone method that returns this. It might even cause problems if you were doing something dubious like having mutable state in your enum constants or synchronising on them. The behaviour of such code would be different depending on whether the clone method did proper cloning or just returned this.

所以目的是让clone()方法返回一个不同的对象。不幸的是,它说这不是绝对要求,这使您的建议有效,但我仍然认为这是不明智的,因为拥有返回this. 如果您正在做一些可疑的事情,例如在您的枚举常量中具有可变状态或同步它们,它甚至可能会导致问题。此类代码的行为会有所不同,具体取决于 clone 方法是正确克隆还是刚刚返回this

You don't really explain why you want to treat enums as Cloneablewhen they are inherently un-cloneable. Wanting to have a clone method that doesn't obey the accepted conventions seems like a hack to solve some more fundamental problem with your approach.

您并没有真正解释为什么要将枚举视为Cloneable本质上不可克隆的。想要拥有一个不遵守公认约定的克隆方法似乎是一种用你的方法解决一些更基本问题的黑客。

回答by Joonas Pulakka

I guess they didn't want to treat singletons as a special case when clone()was specified. That would have complicated the specification. So now the library developers have to treat them as a special case, but for the rest of us, it's nice that we can trust that x.clone() != x.

我猜他们不想clone()在指定时将单身人士视为特殊情况。那会使规范复杂化。因此,现在库开发人员必须将它们视为一种特殊情况,但对于我们其他人来说,很高兴我们可以信任它x.clone() != x

回答by jprete

Your own answer to your question is the best one. In general, people expect clone()to give back a different object. The semantics of Cloneableitself make more sense that way. ("The object is cloneable...oh, I must be able to make copies.") I can't think of a situation offhand where that matters, but that was the intended semantic meaning of Cloneable.

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

I think that even if they were thinking about singletons, they would not have changed it. After all, it's the programmer's responsibility to decide what can be cloned and what can't, by selectively adding (and potentially overriding) the Cloneableinterface, and most programmers are not going to add the Cloneableinterface to singletons either.

我认为即使他们正在考虑单身人士,他们也不会改变它。毕竟,通过有选择地添加(并可能覆盖)Cloneable接口来决定哪些可以克隆,哪些不能克隆是程序员的责任,而且大多数程序员也不打算将Cloneable接口添加到单例中。

回答by Pascal Thivent

But for singletons on the contrary I want x.clone() == xto be true.

但对于单身人士相反,我想x.clone() == x是真的。

No, that wouldn't be a clone. So, for singletons, you want this:

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

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