[英]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,因为对我的理解如下。
super.clone()方法将创建一个父类型的新对象(在本例中为Object),其中父类的属性将被浅复制。
当我们在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.