Why are Java enums not clonable?

二次信任 提交于 2019-12-04 04:11:59

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.

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

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.

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.

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.

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(); 
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!