为什么在java.lang.Object中保护clone()方法?

时间:2009-07-16 16:28:37

标签: java oop clone

java.lang.Object中将clone()定义为受保护的具体原因是什么?

11 个答案:

答案 0 :(得分:100)

克隆受到保护的事实非常可疑 - 因为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接口的目的是作为一个mixin接口,用于宣传他们允许克隆的对象。不幸的是,它无法达到这个目的......这是一个非常非典型的接口使用,而不是一个被模拟的...为了实现接口对某个类产生任何影响,它及其所有超类必须遵守相当复杂,无法执行且基本上未记录的协议

答案 1 :(得分:26)

Clonable接口只是一个标记,表示该类可以支持克隆。该方法受到保护,因为您不应该在对象上调用它,您可以(并且应该)将其覆盖为public。

来自Sun:

在类Object中,clone()方法被声明为protected。如果你所做的只是实现Cloneable,那么只有子类和同一个包的成员才能在对象上调用clone()。要使任何包中的任何类能够访问clone()方法,您必须覆盖它并将其公开,如下所示。 (当你重写一个方法时,你可以减少它的私密性,但不能更私密。这里,Object中的protected clone()方法被覆盖为公共方法。)

答案 2 :(得分:7)

clone受到保护,因为它应该被覆盖,以便它特定于当前类。虽然可以创建一个公共clone方法来克隆任何对象,但这种方法不如专门为需要它的类编写的方法好。

答案 3 :(得分:4)

Clone方法不能直接用于任何对象,这就是为什么它要被子类覆盖。

当然它可能是公开的,只是在无法克隆时抛出适当的例外,但我认为这会产生误导。

现在实现克隆的方式可以让您思考为什么要使用克隆,以及如何克隆对象。

答案 4 :(得分:2)

它受到保护,因为默认实现执行所有字段(包括私有),规避构造函数的浅成员副本。这不是一个对象可能被设计为首先处理的东西(例如,它可能跟踪共享列表中创建的对象实例,或类似的东西)。

出于同样的原因,如果调用它的对象没有实现clone(),则Cloneable的默认实现将抛出。这是一个潜在的不安全操作,具有深远的影响,因此该类作者必须明确选择加入。

答案 5 :(得分:2)

来自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,但这会给你大部分时间而不是你想要的结果或异常。但只有在实现cloneable时才会受到鼓励。

答案 6 :(得分:2)

恕我直言,这很简单:

    不能在非可克隆对象上调用
  • #clone,因此它不会公开
  • #clone必须由子类ob Object调用,它实现Cloneable以获取正确类的浅层副本

什么是适合子类调用的方法的范围,而不是其他类可调用的范围?

它是protected

实现Cloneable的类当然会使这个方法公开,所以可以从其他类调用它。

答案 7 :(得分:0)

Clone()方法内部有一个'Cloneable实例'检查,这就是Java团队可能会认为将限制对clone()方法的不当使用.clone()方法是受保护的,即只能由子类访问。由于object是所有子类的父类,因此,如果我们没有对“ Cloneable的实例”进行以上检查,则实际上所有类都可以使用Clone()方法。这就是Java团队可能会考虑通过在clone()方法中检查“它是否为Cloneable实例”来限制不当使用clone()的原因。

因此,任何实现可克隆的类都可以使用Object类的clone()方法。

此外,由于它已受到保护,因此它仅对实现可克隆接口的那些子类可用。如果要使其公开,则子类必须使用其自己的实现来重写此方法。

答案 8 :(得分:-2)

是的,我遇到了同样的问题。 但我通过实现此代码来解决它

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;
    }
}

就像之前有人说的那样。

答案 9 :(得分:-2)

嗯,太阳开发人员也只是人类,他们确实犯了很大的错误,将克隆方法实现为受保护,这与他们在ArrayList中实现一个无效的克隆方法一样!因此,总的来说,即使是经验丰富的Java程序员也对克隆方法存在更深层次的误解。

但是,我最近发现了一个快速简便的解决方案来复制任何包含其所有内容的对象,无论它是如何构建的以及它包含的内容,请参阅我的答案:Bug in using Object.clone()

答案 10 :(得分:-3)

再次,Java JDK框架显示了出色的思维:

可克隆接口不包含“public T clone();”方法因为它更像是一个属性(例如Serializable),它允许克隆一个实例。

此设计没有任何问题,因为:

  1. 对象.clone()将无法按照自定义类进行操作。

  2. 如果你有Myclass实现Cloneable =&gt;你用。覆盖clone() “public MyClass clone()”

  3. 如果你有MyInterface扩展Cloneable和一些MyClasses实现MyInterface: 简单地定义“public MyInterface clone();”在接口中,使用MyInterface对象的每个方法都可以克隆它们,无论它们是MyClass类。