为什么Object clone()方法仅适用于实现Cloneable接口的类?

时间:2013-08-14 18:58:11

标签: java object cloneable

我知道clone()是受保护的方法,但“受保护”意味着它可以被特定类的所有子类访问。

任何Java类都是Object的子类,那么受保护方法的原因是什么?

为什么我们只能在实现clone()接口的类上调用Cloneable? 我无法理解它与clone()Object被声明为受保护的事实有什么联系。

6 个答案:

答案 0 :(得分:11)

Object的clone()方法非常特殊,因为它总是返回当前类的一个实例,它复制了所有字段(甚至是最终的)。我不认为用普通的Java代码重现这一点,甚至不用反射。

因此,它必须对所有类都可用,但由于它不能从外部调用,因为你不希望所有东西都是可复制的,所以它必须受到保护。

作为附加检查,clone检查该类是否实现了Cloneable,只是为了确保您不会意外克隆非可复制的文件。


总而言之,克隆有点破坏,因为当您需要深度复制最终字段时,它不起作用。我建议您按照此模式手动实施实例复制。

public class Base {

    /** one or more public constructors */
    public Base() { ... }

    /** copy-constructor */
    protected Base(Base src) { /* copy or deep-copy the state */ }

    public Base copy() { return new Base(this); }
}

public class Derived extends Base {

    /** one or more public constructors */
    public Derived() { ... }

    /** copy-constructor */
    protected Derived(Derived src) { 
        super(src);
        /* copy or deep-copy the state */ 
    }

    @Override
    public Derived copy() { return new Derived(this); }
}

答案 1 :(得分:4)

因为这是他们设计它的方式。在Bug Parade的某个地方有一个声明,设计的最初原因是“迷失在时间的迷雾中”,但我记得Sun在20世纪90年代的一次讨论中说设计给出了四种可能的行为。

不记得细节: - |但你可以解决这个问题:

  1. 什么都不做。无法克隆类,除派生类外,clone()方法不可访问。
  2. 实现Cloneable:可以克隆类,但除派生类外,clone()方法不可访问。
  3. 实施Cloneable并提供您自己的clone()方法:as(2)但是有可能使clone()公开,现在也可以返回正确的类型。
  4. 派生自(2)或(3)的类,实施clone(),然后抛出NotCloneableException:,您将回到1。
  5. clone()放入界面会失去一些。

答案 2 :(得分:3)

Object.clone()的默认实现是唯一的方法(除了可能是Reflection),通过该方法,对象中的基类型方法可以生成该对象的相同类型的新对象。另一方面,有许多类,派生类不可能实现不违反基类不变量的工作clone方法。希望不允许这样的派生类调用clone并接收一个无法使用的对象。

回想起来,正确的做法可能是定义一个继承自CloneableObject的{​​{1}}系统,其中包含一个受保护的Object方法(类似于memberwiseclone现在没有其他任何东西,并且所有可克隆的类都继承自它作为它们的基类型。该类型可以在其Object.clone()方法中使用其他类型无法使用的特殊魔法。但是,系统使用clone()接口的存在来决定是否允许对象使用基级Cloneable方法。不是一个伟大的设计,但它是它的本质。很难说是否比允许几乎所有派生类调用clone()的.NET方法更好或更差,无论派生类是否有任何方式可以这样做而不会产生破坏的对象。

答案 3 :(得分:2)

Cloneable是一个接口,为了克隆对抽象基类的引用,基类必须具有clone()方法,或者其父类之一必须具有可公开访问的clone()方法。 Cloneable只是一个标记界面。

请参阅:

答案 4 :(得分:1)

http://docs.oracle.com/javase/7/docs/api/java/lang/Cloneable.html

  

一个类实现了Cloneable接口,以向Object.clone()方法指示该方法合法地为该类的实例创建一个字段的字段副本。   在未实现Cloneable接口的实例上调用Object的clone方法会导致抛出CloneNotSupportedException异常。

     

按照惯例,实现此接口的类应使用公共方法覆盖Object.clone(受保护)。有关重写此方法的详细信息,请参阅Object.clone()。

     

请注意,此接口不包含克隆方法。因此,仅仅通过实现该接口的事实来克隆对象是不可能的。即使反射调用clone方法,也无法保证它会成功。

即使对象具有受保护的方法clone Object未实现Cloneable,仍然会出现您的问题,但被称为clone()方法的对象必须实现Cloneable {{1 }}

答案 5 :(得分:-1)

克隆是marker interface。 clone()方法未由Cloneable接口定义。

Object类中的clone方法受到保护,以防止客户端类调用它 - 只有子类可以调用或覆盖clone,并且这样做是bad idea