繁体   English   中英

调用super.clone()方法时向下转换

[英]Downcasting while calling super.clone() method

考虑以下程序

class A implements Cloneable {
    String str = null;
    public void set(String str)
    {
        this.str = str;      
    }

    @Override
    public A clone()
    {
         A a = null;
         try {
              a = (A) super.clone();
              if(a.str!=null) {
                  System.out.println(a.str);
              }
              else {
                  System.out.println("null");
              }

         } 
         catch (CloneNotSupportedException e) {
               e.printStackTrace();
         }
         return a;    
    }
    public static void main (String args[])
    {
        A a = new A();
        a.set("1234");
        A b = a.clone();
    }
}

为什么上述程序的输出是1234而不是null。

我期待null,因为对我的理解如下。

  1. super.clone()方法将创建一个父类型的新对象(在本例中为Object),其中父类的属性将被浅复制。

  2. 当我们在clone()方法中进行向下转换时,子类中定义的属性将使用其默认值进行初始化,因为这是一个新对象。

但是在查看输出之后,似乎子类(this)的当前实例的属性值被复制到新构造的对象中(在调用父类的克隆并向下转换之后)。

有人能告诉我们当我们垂头丧气时发生了什么吗?

正确的结果是1234 ...让我们看看原因:

创建一个新的A实例:

A a = new A();

将值设置为A.str

a.set("1234");

克隆一个

A b = a.clone();

首先,请注意,我们正在使用实例a clone()方法,所以我们去那里:

@Override
public A clone()
{
     // create a NEW instance, it does not set a to null!!!
     // to reference the caller (a.clone in main) 
     // you must use this keyword i.e: this.str = null
     A a = null;
     try {
          // call Cloneable::clone() method 
          a = (A) super.clone();

          // now a is filled with data of this instance so print 1234
          if(a.str!=null) {
              System.out.println(a.str);
          }
          // unused code in this case
          else {
              System.out.println("null");
          }

     } 
     catch (CloneNotSupportedException e) {
           e.printStackTrace();
     }
     // return cloned instance
     return a;    
}

来自Object#clone文档。

创建并返回此对象的副本。 “复制”的确切含义可能取决于对象的类别。 通常的意图是,对于任何对象x,表达式:

x.clone()!= x

将为真,并且该表达式:

x.clone()。getClass()== x.getClass()

是正确的,但这不是绝对要求。 通常情况是:

x.clone()。equals(x)

是真的,这不是绝对要求。

如您所见,典型的情况是X.equals(XClone) == true 对于您而言,情况并非如此,因为A没有覆盖equals方法。

另外:

类Object的方法clone执行特定的克隆操作。

[...]

该方法创建该对象类的新实例,并使用该对象相应字段的内容完全初始化其所有字段,就像通过赋值一样; 字段的内容本身不会被克隆。 因此,此方法执行此对象的“浅复制”,而不是“深复制”操作。

如本文档所述,本机实现只是创建您要克隆的对象的shallow copy 由于这种行为,正确的输出是1234而不是null ,因为类中的fields只是分配给了克隆的实例。

super.clone()方法将创建一个父类型的新对象(在这种情况下为Object)

不,这是您要出问题的地方。 Object.clone()将创建一个新的实例,该实例与调用它的对象的运行时类相同,该运行时类是A ,而不是Object 它将把被调用对象中A所有字段浅拷贝到新对象中。

当我们在clone()方法中进行向下转换时,子类中定义的属性将使用其默认值进行初始化,因为这是一个新对象。

这没有任何意义,因为强制转换引用将永远不会影响所指向对象的状态。 如果引用所指向的对象还不是A的实例,则强制转换将抛出ClassCastException 如果强制转换成功,则意味着引用指向的对象已经是A的实例,而您只是使用不同类型的引用指向同一对象。 您将永远不会获得带有演员表的“新对象”。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM