【问题标题】:Java - understanding cloningJava - 了解克隆
【发布时间】:2013-04-15 04:27:59
【问题描述】:

今天我在计算机科学课上展示了这段代码(附带几个与这篇文章无关的问题)。这不是功课,只是我个人在代码中发现的一些问题;

public class CloneClass implements Cloneable {
    private Element element ;

    public CloneClass ( Element newElement ) {
        element = newElement ;
    }

    public CloneClass clone () {
        try {
            // I don't understand this
            CloneClass copy = ( CloneClass ) super.clone ();
            // or this
            copy.element = element.clone ();

            return copy ;
        } catch ( CloneNotSupportedException e ) {
            return null ;
        }
    }
}

首先;

CloneClass copy = ( CloneClass ) super.clone ();

我们知道 super 是 Object(因为没有显式扩展)并且 super.clone() 必须返回 CloneClass 的实例(它不能返回 Object 实例,因为那是抽象的,而且它正在向下转换到CloneClass,所以它必须是CloneClass 或后代实例)。
我的问题; super.clone() 怎么知道返回 CloneClass 实例?

其次;

copy.element = element.clone ();

怎么可能这样直接引用copy.element;它被宣布为私有的!
它不是当前类的属性,而是另一个实例的属性(恰好是同一个类)

第三;

} catch ( CloneNotSupportedException e ) {

为什么需要这个?这是 Element 不扩展 Cloneable 吗?

【问题讨论】:

    标签: java clone private super


    【解决方案1】:

    super.clone() 如何知道返回一个 CloneClass 实例?

    即使在 super 方法中,this 仍然指向同一个对象,因此 this.getClass() 会为您提供 CloneClass(甚至是子类)。

    怎么可能像这样直接引用copy.element;它被声明为私有的!

    您不仅可以访问this 的私有字段,还可以访问同一类的其他实例。它只对其他类是私有的。

    为什么需要这个?这是 incase Element 不扩展 Cloneable 吗?

    因为CloneClass 可能不会扩展 Cloneable(它显然是这样做的,但是由于这个 API 是如何设计的 Object#clone 抛出 CloneNotSupportedException,编译器无法建立这种连接)。

    这在 Java 中有点丑陋的设计缺陷。 Object 有一个clone 方法,但 Object 本身不可克隆(这是一个标记接口)。因此,您可以在不支持它的对象上调用该方法。与 Serializable 类似。

    【讨论】:

    • 我不确定我是否理解“即使在一个超级方法中,this 仍然指向同一个对象,所以this.getClass() 会给你CloneClass(甚至是一个子类)。”这是否意味着如果超类(在本例中为对象)有一个返回 this.getClass() 的方法,并且您从 CloneClass 调用它,它会返回 CloneClass? (即使它是超级中的一种方法?)
    • 是的。 this 始终指向当前的实际实例。你会得到CloneClass
    • 哦,所以 super 真的只是为了让 Java 在那里查找字段。它仍然是同一实例的“一部分”吗?非常感谢!
    • 在您的情况下,super 用于调用超类中方法的实现。这是在覆盖方法时扩展实现的常见模式。使用clone() 而不是super.clone(),您最终会得到无限递归(该方法只是再次调用自身)。
    【解决方案2】:

    Object#clone签名是

    受保护对象 clone() 抛出 CloneNotSupportedException

    它复制包含被克隆对象的内部“深层结构”的任何可变对象并返回Object,因此您需要将其转换为CloneClass的对象类型。

    copy.element = element.clone();

    你可以引用私有字段,因为你和它自己在同一个班级。

    } 捕捉 (CloneNotSupportedException e) {

    Object#clone 抛出 CloneNotSupportedException 如果对象的类不支持 Cloneable 接口。覆盖 clone 方法的子类也可以抛出这个异常,表示实例不能被克隆。

    【讨论】:

    • CloneNotSupportedException 是运行时异常吗?
    • 那么为什么我必须有一个 try and catch 块?如果Element没有实现Cloneable,代码本身不应该编译吗??
    • 是的,你必须这样做,因为它是Checked Exception。编译器不会要求实施,但如果您不这样做,它将引发Exception
    【解决方案3】:

    1) Object.clone API 声明对于任何对象 x,x.clone().getClass() == x.getClass() 为真

    2) 可以访问私有的copy.element,因为我们在同一个类中访问它

    3) 如果Element没有实现Cloneable,element.clone()会抛出CloneNotSupportedException,会被捕获并返回null

    【讨论】:

    • 我认为1) 根本不会回答任何问题;我更好奇x.super.clone().getClass() == x.getClass()
    【解决方案4】:
    // I don't understand this
    CloneClass copy = ( CloneClass ) super.clone ();
    

    构造此对象的副本,按位复制其所有成员,包括原始类型和引用类型。

    // or this
    copy.element = element.clone ();
    

    见上文。在此行之前,copy.element 指向与this.element 相同的对象。此行克隆了它,因此它们现在指向不同的元素,因此 this 的克隆现在完全独立于 this

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-09-12
      • 2015-05-17
      • 2011-08-25
      • 1970-01-01
      • 1970-01-01
      • 2013-03-23
      • 2011-11-14
      • 1970-01-01
      相关资源
      最近更新 更多