Answers:
克隆受到保护的事实非常令人怀疑-事实是该clone
方法未在Cloneable
接口中声明。
它使该方法对于获取数据副本非常无用,因为您不能说:
if(a instanceof Cloneable) {
copy = ((Cloneable) a).clone();
}
我认为,Cloneable
现在的设计在很大程度上被认为是一个错误(以下引用)。我通常希望能够实现一个接口的实现,Cloneable
但不一定要实现该接口Cloneable
(类似于的使用Serializable
)。没有反思就无法做到这一点:
ISomething i = ...
if (i instanceof Cloneable) {
//DAMN! I Need to know about ISomethingImpl! Unless...
copy = (ISomething) i.getClass().getMethod("clone").invoke(i);
}
乔什·布洛赫(Josh Bloch)的《有效Java 》的引文:
“ Cloneable接口旨在作为对象的混合接口,以宣告它们允许克隆。不幸的是,它不能满足这一目的……这是一种非常不典型的接口使用,而不是一个可被模仿的接口......为了实现这些接口有一个类有任何影响,它和所有超类必须遵守一个相当复杂的,不能强制执行,并在很大程度上无证协议 “
Serializable
-由实现决定是否实现Serializable
。我将其扩展为Cloneable
-这不是接口应该扩展的内容-但是接口的实现是自由的Cloneable
。麻烦的是,如果您具有接口类型的参数,则询问它是否可克隆;但是您实际上无法克隆它!
Clonable接口只是一个标记,表明该类可以支持克隆。该方法受到保护,因为您不应该在对象上调用它,您可以(并且应该)将其重写为公共方法。
从太阳出发:
在Object类中,clone()方法被声明为protected。如果您所做的只是实现Cloneable,则只有同一个包的子类和成员才能在对象上调用clone()。要使任何包中的任何类都可以访问clone()方法,您必须重写它并将其声明为公共,如下所示。(重写方法时,可以使它的私有性降低,但不能使其私有化。这里,Object中受保护的clone()方法将被重写为公共方法。)
Set
clone
之所以受到保护,是因为它是应该被覆盖的东西,因此它特定于当前类。尽管有可能创建一个clone
完全克隆任何对象的公共方法,但这并不像为需要它的类专门编写的方法那样好。
之所以受到保护,是因为默认实现会绕过构造函数对所有字段(包括私有字段)进行浅成员复制。最初,这不是一个对象可以设计用来处理的东西(例如,它可能会在共享列表中跟踪创建的对象实例,或者类似的东西)。
出于同样的原因,clone()
如果调用的对象未实现,则默认的实现会抛出Cloneable
。这是一种潜在的不安全操作,会产生深远的后果,因此该类的作者必须明确选择加入。
来自可克隆的javadoc。
* By convention, classes that implement this interface (cloneable) should override
* <tt>Object.clone</tt> (which is protected) with a public method.
* See {@link java.lang.Object#clone()} for details on overriding this
* method.
* Note that this interface does <i>not</i> contain the <tt>clone</tt> method.
* Therefore, it is not possible to clone an object merely by virtue of the
* fact that it implements this interface. Even if the clone method is invoked
* reflectively, there is no guarantee that it will succeed.
因此,您可以在每个对象上调用clone,但这在大多数情况下不会给您想要的结果或例外。但是仅当您实现可克隆时才鼓励这样做。
恕我直言,就是这样简单:
#clone
不能在非克隆对象上调用,因此它不会公开#clone
必须由Object
实现Cloneable 的子类ob调用,以获取正确类的浅表副本子类可调用但其他类不能调用的方法的正确范围是什么?
是protected
。
Cloneable
当然,实现类的方法将使此方法公开,因此可以从其他类中调用它。
Clone()方法内部有一个'Cloneable实例是否可用'的检查。Java团队可能会认为这会限制对clone()方法的不当使用。clone()方法受保护,即只能由子类访问。由于object是所有子类的父类,因此,如果我们没有对“ Cloneable的实例”进行上述检查,那么所有类实际上都可以使用Clone()方法。这就是Java团队可能会考虑通过在clone()方法中检查“是否为Cloneable实例”来限制对clone()的不当使用的原因。
因此,任何实现可克隆的类都可以使用Object类的clone()方法。
同样,由于它已受到保护,因此它仅对实现可克隆接口的那些子类可用。如果我们想将其公开,则子类必须使用其自己的实现来重写此方法。
是的,我遇到了同样的问题。但是我通过实现这段代码来解决
public class Side implements Cloneable {
public Side clone() {
Side side = null;
try {
side = (Side) super.clone();
} catch (CloneNotSupportedException e) {
System.err.println(e);
}
return side;
}
}
就像之前有人说的那样。
好吧,Sun开发人员也只是人类,他们确实犯了巨大的错误,无法将克隆方法实现为受保护,这与他们在ArrayList中实现无效的克隆方法时一样!因此,一般而言,即使是经验丰富的Java程序员也对克隆方法存在更深的误解。
但是,我最近找到了一种快速简便的解决方案,可以复制任何对象及其所有内容,无论它是如何构建的以及包含什么内容,请在此处查看我的答案:使用Object.clone()的错误
Java JDK框架再次展示了出色的思想:
可克隆的接口不包含“ public T clone();”。方法,因为它的作用更像是允许克隆其实例的属性(例如,Serializable)。
此设计没有错,因为:
Object.clone()不会对您定义的类执行您想要的操作。
如果您具有Myclass实现Cloneable =>,则可以使用“ public MyClass clone()”覆盖clone()
如果您拥有MyInterface扩展Cloneable和一些实现MyInterface的MyClasses:只需定义“ public MyInterface clone();”即可。在界面中,使用MyInterface对象的每个方法都可以克隆它们,无论它们是MyClass类。