116

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

4

11 回答 11

108

克隆受保护的事实非常可疑 -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 的 Effective Java 的引文:
“Cloneable 接口旨在作为对象的混合接口,以宣传它们允许克隆。不幸的是,它无法达到此目的......这是一种非常不典型的接口使用,不是一个可以模拟的接口...为了实现接口对一个类产生任何影响,它和它的所有超类必须遵守一个相当复杂、不可执行且大部分未记录的协议

于 2009-07-16T16:32:48.003 回答
30

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

来自太阳:

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

于 2009-07-16T16:38:54.857 回答
8

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

于 2009-07-16T16:30:29.290 回答
4

Clone 方法不能直接在任何对象上使用,这就是它打算被子类覆盖的原因。

当然它可以是公开的,并且在无法克隆时抛出适当的异常,但我认为这会产生误导。

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

于 2009-07-16T16:34:10.217 回答
3

恕我直言,就像这样简单:

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

应该由子类调用但不能由其他类调用的方法的正确范围是什么?

protected

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

于 2016-09-05T12:35:36.783 回答
2

它是受保护的,因为默认实现对所有字段(包括私有)进行了浅成员复制,从而绕过了构造函数。这不是一个对象可能被设计为首先处理的事情(例如,它可能会跟踪共享列表中创建的对象实例,或类似的东西)。

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

于 2009-07-16T16:34:49.437 回答
2

来自可克隆的 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 ,但这在大多数情况下会给您带来不想要的结果或异常。但仅在您实现可克隆时才鼓励使用。

于 2009-07-16T16:38:30.723 回答
0

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

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

此外,由于它是受保护的,因此它仅对那些实现可克隆接口的子类可用。如果我们想让它公开,这个方法必须被子类用他们自己的实现覆盖。

于 2018-08-17T21:07:23.737 回答
-1

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

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

就像之前有人说的那样。

于 2009-08-10T16:55:17.580 回答
-2

好吧,sun 开发人员也只是人类,他们确实犯了很大的错误,将克隆方法实现为受保护的,与他们在 ArrayList 中实现无功能的克隆方法一样的错误!因此,一般来说,即使是经验丰富的 Java 程序员也对克隆方法存在更深的误解。

但是,我最近找到了一种快速简便的解决方案,可以复制任何对象及其所有内容,无论它是如何构建的以及它包含什么,请在此处查看我的答案:使用 Object.clone() 中的错误

于 2012-10-21T12:47:19.730 回答
-4

再次,Java JDK 框架展现了绝妙的思维:

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

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

  1. Object.clone() 不会对您的自定义类执行您想要的操作。

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

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

于 2010-05-31T19:21:30.653 回答