Java:super.clone() 方法和继承
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11905630/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java: super.clone() method and inheritance
提问by Shuzheng
I have a quick question regarding the clone()
method in Java, used as super.clone()
in regard to inheritance - where I call the clone()
method in the parent class all the way up from the button.
我有一个关于clone()
Java 中的方法的快速问题,用作super.clone()
关于继承 - 我clone()
从按钮一直调用父类中的方法。
The clone()
method is supposed to return a copy of this object, however if I have three classes in an inheritance heirachy and call super.clone()
three times, why doesn't the highest class in the inheritance heirachy, just under class Object, get a copy of that class returned?
该clone()
方法应该返回此对象的副本,但是如果我在继承层次中有三个类并调用super.clone()
了三次,为什么继承层次中的最高类,就在类 Object 下,获取该类的副本回?
Suppose we have three classes: A, B and C, where A -> B -> C (inherit = ->)
假设我们有三个类:A、B 和 C,其中 A -> B -> C(继承 = ->)
Then calling super.clone()
in class C, invokes clone()
in B which calls super.clone()
, invoke clone()
in A which call super.clone()
'this time Object.clone() gets called'. Why is it not a copy of the this
object with respect to class A that gets returned from Object.clone()
? That sounds logical to me.
然后super.clone()
在类 C 中调用,clone()
在 B 中调用super.clone()
,在 B 中调用,clone()
在 A 中调用,调用super.clone()
'这次调用Object.clone()'。为什么它不是this
从 返回的类 A的对象副本Object.clone()
?这对我来说听起来很合乎逻辑。
采纳答案by Bob Cross
It sounds like there are at least two problems at work here:
听起来这里至少有两个问题在起作用:
It sounds like you're confused about how clone() normally gets implemented.
It sounds like you're thinking that cloning is a good idea (vs. using a copy constructor, factories or their equivalent).
听起来您对通常如何实现 clone() 感到困惑。
听起来您认为克隆是一个好主意(与使用复制构造函数、工厂或它们的等价物相比)。
Here is an example of an implementationof a clone method:
下面是一个克隆方法的实现示例:
@Override
public Object clone() throws CloneNotSupportedException {
//get initial bit-by-bit copy, which handles all immutable fields
Fruit result = (Fruit)super.clone();
//mutable fields need to be made independent of this object, for reasons
//similar to those for defensive copies - to prevent unwanted access to
//this object's internal state
result.fBestBeforeDate = new Date( this.fBestBeforeDate.getTime() );
return result;
}
Note that the result of super.clone()
is immediately cast to a Fruit
. That allows the inheriting method to then modify the Fruit-specific member data (fBestBeforeDate
in this case).
请注意, 的结果super.clone()
会立即转换为Fruit
。这允许继承方法然后修改 Fruit-specific 成员数据(fBestBeforeDate
在这种情况下)。
Thus, the call to a child clone()
method, while it will call the parents' clones, also adds its own specific modifications to the newly made copy. What comes out, in this case, will be a Fruit
, not an Object
.
因此,对子clone()
方法的调用,在调用父方法的克隆的同时,也会向新创建的副本添加自己的特定修改。在这种情况下,出来的将是Fruit
,而不是Object
。
Now, more importantly, cloning is a bad idea. Copy constructors and factories provide much more intuitive and easily maintained alternatives. Try reading the header on the Java Practiceslink that I attached to the example: that summarizes some of the problems. Josh Bloch also has a much longer discussion: cloning should definitely be avoided. Here is an excellent summary paragraph on why he thinks cloning is a problem:
现在,更重要的是,克隆是一个坏主意。复制构造函数和工厂提供了更直观且易于维护的替代方案。尝试阅读我附加到示例的Java 实践链接上的标题:它总结了一些问题。Josh Bloch 也有一个更长的讨论:绝对应该避免克隆。以下是关于为什么他认为克隆是一个问题的出色总结段落:
Object's clone method is very tricky. It's based on field copies, and it's "extra-linguistic." It creates an object without calling a constructor. There are no guarantees that it preserves the invariants established by the constructors. There have been lots of bugs over the years, both in and outside Sun, stemming from the fact that if you just call super.clone repeatedly up the chain until you have cloned an object, you have a shallow copy of the object. The clone generally shares state with the object being cloned. If that state is mutable, you don't have two independent objects. If you modify one, the other changes as well. And all of a sudden, you get random behavior.
Object 的 clone 方法非常棘手。它基于现场副本,并且是“超语言的”。它在不调用构造函数的情况下创建一个对象。不能保证它保留构造函数建立的不变量。这些年来,无论是在 Sun 公司内部还是外部,都存在许多错误,因为如果您只是在链上重复调用 super.clone 直到您克隆了一个对象,那么您就有了该对象的浅拷贝。克隆通常与被克隆的对象共享状态。如果该状态是可变的,则您没有两个独立的对象。如果您修改其中一个,则另一个也会更改。突然之间,您会出现随机行为。
回答by oarfish
Although one answer is accepted, I do not think it fully answers the first part of the question (why downcasting in subclasses always works). Although I cannot really explain it, I think I can clear up some of the poster's confusion which was the same as mine. We have the following classes
尽管接受了一个答案,但我认为它并没有完全回答问题的第一部分(为什么在子类中向下转换总是有效)。虽然我无法真正解释它,但我想我可以澄清一些海报与我相同的困惑。我们有以下课程
class A implements Cloneable
{
@Override
protected A clone() throws CloneNotSupportedException // could be public
{
Object clone = super.clone();
System.out.println("Class A: " + clone.getClass()); // will print 'C'
return (A) clone;
}
}
class B extends A
{
@Override
protected B clone() throws CloneNotSupportedException
{
A clone = super.clone();
System.out.println("Class B: " + clone.getClass()); // will print 'C'
return (B) clone;
}
}
class C extends B
{
@Override
protected C clone() throws CloneNotSupportedException
{
B clone = super.clone();
System.out.println("Class C: " + clone.getClass()); // will print 'C'
return (C) clone;
}
}
static main(char[] argv)
{
C c = new C();
C cloned_c = c.clone();
}
The result of this is that
这样做的结果是
Class A: C
Class A: C
Class B: C
Class B: C
Class C: C
Class C: C
is printed on the command line.
So, as a matter of fact, the clone()
method of Object
somehow can look downthe call stack and see which type of object at the start of the chaininvoked clone()
, then, provided the calls bubble up so that Object#clone()
is actually called, an object of that type is created. So this happens already in class C
, which is strange, but it explains why the downcasts do not result in a ClassCastException
. I've checked with the OpenJDK, and it appears this comes by some Java black magic implemented in native code.
打印在命令行上。所以,事实上,该clone()
方法Object
在某种程度上可以看看下调用栈,看看对象的哪些类型在链开始被调用clone()
,那么,所提供的电话泡了,这样Object#clone()
实际上是所谓的,该类型的对象被建造。所以这已经发生在 class 中C
,这很奇怪,但它解释了为什么向下转换不会导致ClassCastException
. 我已经检查过 OpenJDK,这似乎是由在本机代码中实现的一些 Java 黑魔法造成的。
回答by evg
Its a special native method. This was done to make cloning easier. Otherwise you will have to copy the whole code of your ancestor classes.
它是一种特殊的本地方法。这样做是为了使克隆更容易。否则,您将不得不复制祖先类的整个代码。
回答by Bhesh Gurung
If clone() in B returns whatever clone() in A returns and clone() in C returns whatever the clone() in B returns then clone() in C will return whatever the clone() in A returns.
如果 B 中的 clone() 返回 A 中的 clone() 返回,而 C 中的 clone() 返回 B 中的 clone() 返回的任何内容,则 C 中的 clone() 将返回 A 中的 clone() 返回的任何内容。
回答by Tejaswitachauhan
this class has information about this class as well as it is associated with another class. So, conceptually this class's object will have information of associated class as well. this object is incomplete object without associated object/parent class.all direct as well as indirect fields in this class needs to be copied make it a worth it new clone of current object. we cannot access only that portion of reference which only denotes child section.
这个类有关于这个类的信息以及它与另一个类相关联。因此,从概念上讲,此类的对象也将具有关联类的信息。这个对象是不完整的对象,没有关联的对象/父类。这个类中的所有直接和间接字段都需要复制,使其成为当前对象的新克隆。我们不能只访问仅表示子部分的参考部分。