考虑以下计划
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。
由于对我的了解,我期待无效。
super.clone()方法将创建父类型的新对象(在本例中为Object),其中父类的属性将被浅层复制。
当我们在clone()方法中进行向下转换时,子类中定义的属性将使用其默认值进行初始化,因为这是一个新对象。
但是在查看输出之后,似乎将子类(this)的当前实例的属性值复制到新构造的对象(在调用父类的克隆和向下转换之后)。
当我们向下倾斜时,有人可以告诉我们发生了什么事吗?
答案 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
的实例,并且您只是指向具有不同类型引用的同一对象。你永远不会得到一个演员的“新对象”。