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

时间:2016-08-08 11:36:01

标签: java downcast cloneable

考虑以下计划

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。

由于对我的了解,我期待无效。

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

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

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

    当我们向下倾斜时,有人可以告诉我们发生了什么事吗?

3 个答案:

答案 0 :(得分:1)

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

创建一个新的A实例:

A a = new A();

将值设置为A.str

a.set("1234");

克隆

A b = a.clone();

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

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

答案 1 :(得分:1)

来自Object#clone文档。

  

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

     

x.clone()!= x

     

将是真的,表达式为:

     

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

     

将是真的,但这些并非绝对要求。虽然通常情况如下:

     

x.clone()。等于(x)的

     

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

如您所见,典型案例是X.equals(XClone) == true。 这不是你的情况,因为A没有覆盖equals方法。

Additonally:

  

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

     

[...]

     

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

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

答案 2 :(得分:0)

  

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

没有。这是你出错的地方。 Object.clone()将创建与调用它的对象的运行时类相同的运行时类的新实例,即A,而不是Object。它会将调用它的对象中A的所有字段浅层复制到新对象中。

  

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

这没有任何意义,因为转换引用永远不会影响指向的对象的状态。如果引用指向的对象不是A的实例,则转换将抛出ClassCastException。如果转换成功,那么这意味着引用指向的对象已经是A的实例,并且您只是指向具有不同类型引用的同一对象。你永远不会得到一个演员的“新对象”。