有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

调用super时进行java向下转换。clone()方法

考虑以下程序

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且不为空

我希望为空,因为我的理解如下

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

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

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

有人能告诉我当我们情绪低落时发生了什么吗


共 (3) 个答案

  1. # 1 楼答案

    来自Object#clone文档

    Creates and returns a copy of this object. The precise meaning of "copy" may depend on the class of the object. The general intent is that, for any object x, the expression:

    x.clone() != x

    will be true, and that the expression:

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

    will be true, but these are not absolute requirements. While it is typically the case that:

    x.clone().equals(x)

    will be true, this is not an absolute requirement.

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

    此外:

    The method clone for class Object performs a specific cloning operation.

    [...]

    this method creates a new instance of the class of this object and initializes all its fields with exactly the contents of the corresponding fields of this object, as if by assignment; the contents of the fields are not themselves cloned. Thus, this method performs a "shallow copy" of this object, not a "deep copy" operation.

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

  2. # 2 楼答案

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

    创建一个新的A实例:

    A a = new A();
    

    将值设置为A.str

    a.set("1234");
    

    克隆a

    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;    
    }
    
  3. # 3 楼答案

    super.clone() method will create a new object of parent type (Object in this case)

    不,这就是你的错误所在Object.clone()将创建一个新的运行时类实例,该实例与被调用对象的运行时类相同,即A,而不是Object。它会将被调用对象中A的所有字段浅拷贝到新对象中

    When we do downcasting in our clone() method, then attributes defined in child class will get initialised with their default values, since this is a new object.

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