为什么 Java 枚举不可克隆?

发布于 2024-08-12 04:12:46 字数 536 浏览 4 评论 0原文

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


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

该手册指出

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

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

有人可能会争辩说

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

但对于单例,相反,我希望 x.clone() == x 为 true 。如果返回实例本身,那么单例模式对于引用对象来说将是透明的。

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

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.


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

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() != x will be true, [...]

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

べ繥欢鉨o。 2024-08-19 04:12:46

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

严格来说,如果您想克隆某些东西强制x.clone() == x,则唯一可以作为克隆结果的对象是x 本身:

def clone() {
  return this;
}

这可能会产生误导...


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

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

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

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

此岸叶落 2024-08-19 04:12:46

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

Javadoc 说:

按照约定,返回的对象
这个方法应该独立于
这个对象(正在被克隆)。

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

编辑:回应以下评论:

这正是我所批评的。为什么
不返回相同的实例,如果存在
不能是一个不同的吗?

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

总体意图是,对于任何
对象x,表达式:

x.clone() != x

将为 true,并且
表达式:

x.clone().getClass() == x.getClass()

将为 true,但是这些
并非绝对要求。

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

当枚举本质上不可克隆时,您并没有真正解释为什么要将它们视为可克隆的。想要有一个不遵守公认约定的克隆方法似乎是为了解决您的方法中一些更基本的问题。

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

The Javadoc says:

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:

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.

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.

You don't really explain why you want to treat enums as Cloneable when 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.

对你再特殊 2024-08-19 04:12:46

但对于单例,相反,我希望 x.clone() == x 为 true。

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

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()只提供浅拷贝,即使是它的正确实现可能会导致上述代码中的错误。)

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

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

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

You may 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.)

On the other hand, I can sort of agree that it would make sense for cloning operations to just return this for 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).

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 IdentityHashMap or something.

相守太难 2024-08-19 04:12:46

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

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.

毁梦 2024-08-19 04:12:46

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

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

Your own answer to your question is the best one. In general, people expect clone() to give back a different object. The semantics of Cloneable itself 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.

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 Cloneable interface, and most programmers are not going to add the Cloneable interface to singletons either.

最初的梦 2024-08-19 04:12:46

但对于单例,相反,我希望 x.clone() == x 为 true。

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

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

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

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

public Object clone() throws CloneNotSupportedException {
  throw new CloneNotSupportedException(); 
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文