Java 这个克隆()有什么问题?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1052340/
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
What is wrong with this clone()?
提问by Johanna
I have written this clone method for when the parent of the Employee class is abstract and the clone() method in the parent class is abstract.I wanted to copy the primitive data type of the Employee's object with this code instead of copying each primitive data type individually, but this code has problem with the line that I call clone() method. (This code is in Employee class)
当 Employee 类的父类是抽象的并且父类中的 clone() 方法是抽象的时,我已经编写了这个 clone 方法。我想用这段代码复制 Employee 对象的原始数据类型,而不是复制每个原始数据单独键入,但是这段代码在我调用 clone() 方法的那一行有问题。(此代码在 Employee 类中)
public Object clone() {
Object obj = new Object();
Object object = obj.clone(); //Emphasis here
return object;
}
the error is: The method clone() from the type Object is not visible.
错误是:来自 Object 类型的方法 clone() 不可见。
But my Employee class is in the class hierarchy which can access the protected clone() method in the Object class.
但是我的 Employee 类位于可以访问 Object 类中受保护的 clone() 方法的类层次结构中。
This is my simple Employee class:
这是我的简单 Employee 类:
public class Employee extends Person implements Cloneable {
private int ID;
public Employee() {
ID = 0;
}
public void setID(int ID) {
this.ID = ID;
}
public int getID() {
return ID;
}
public Object clone1() throws CloneNotSupportedException {
try {
Object obj = new Object();
Object object = obj.clone();
return object;
} catch (CloneNotSupportedException ex) {
return null;
}
}
采纳答案by akarnokd
Did you implement the Cloneable interface on your object?
您是否在对象上实现了 Cloneable 接口?
However, there are very few cases I would use clone for copying an object. One such safe example is array.clone(). I would rather use the copy-constructor idiom or manually copying / assigning values around.
但是,在极少数情况下我会使用 clone 来复制对象。一个这样的安全示例是 array.clone()。我宁愿使用复制构造函数习语或手动复制/分配值。
There is Item#11 in Effective Java(2nd edition) about the background issue. Cloneable interface is a special kind of interface as it modifies the Object
class' behavior regarding the cloning. Basically it is a feature enabling classinterface in Java.
Effective Java(第 2 版)中有 Item#11关于背景问题。Cloneable 接口是一种特殊的接口,因为它修改了Object
类关于克隆的行为。基本上它是在 Java 中启用类接口的功能。
Edit:Based on your example you might need to wrap the clone() call in a try-catch of CloneNotSupportedException in a general case.
编辑:根据您的示例,在一般情况下,您可能需要将 clone() 调用包装在 CloneNotSupportedException 的 try-catch 中。
Edit2:Rephrased my answer
编辑2:改写我的答案
Edit3:Did you override the clone() in the public
context? In the sample you gave you try to clone an Object, which is in the java.lang package - hardly the package your code is in.
Edit3:你在public
上下文中覆盖了 clone()吗?在您提供的示例中,您尝试克隆一个对象,该对象位于 java.lang 包中 - 几乎不是您的代码所在的包。
Edit4:I think the answer is already in the other posts, just wanted to reflect on the underlying issue.
Edit4:我认为答案已经在其他帖子中了,只是想反思一下潜在的问题。
Edit5:Try this:
编辑5:试试这个:
public Object clone1() throws CloneNotSupportedException {
return super.clone();
}
Edit6Then name your method public abstract Object copy()
for example and in the implementation, use the super.clone() - to avoid confusion.
Edit6然后public abstract Object copy()
例如命名您的方法,并在实现中使用 super.clone() - 以避免混淆。
Edit7I did some eclipsing and came out with the following solution:
Edit7我做了一些日食并得出了以下解决方案:
public class Cloner {
public static abstract class Person {
protected abstract Object clone1() throws CloneNotSupportedException;
public Object copy() throws CloneNotSupportedException {
return clone1();
}
}
public static class Employee extends Person implements Cloneable {
@Override
protected Object clone1() throws CloneNotSupportedException {
return super.clone();
}
}
public static void main(String[] args) throws Exception {
new Employee().copy();
}
}
But basically it is the same concept as renaming your abstract method to something else than clone().
但基本上它与将抽象方法重命名为 clone() 以外的其他内容的概念相同。
Edit8:Fixed my sample, now it works without exception.
Edit8:修复了我的示例,现在它无一例外地工作。
(But the actual credit goes to Gábor Hargitaifor super.clone()
)
(但实际要归功于的Gabor Hargitai为super.clone()
)
回答by dreadwail
Have you implemented the appropriate interface? It may be as simple as that, though you may have already accounted for this.
您是否实现了适当的接口?可能就这么简单,尽管您可能已经考虑到了这一点。
See here for more information: http://java.sun.com/javase/6/docs/api/java/lang/Object.html#clone()
有关更多信息,请参见此处:http: //java.sun.com/javase/6/docs/api/java/lang/Object.html#clone()
回答by Ganesh R.
I am not very familiar with Java but this may help: http://en.wikipedia.org/wiki/Clone_(Java_method)
我对 Java 不是很熟悉,但这可能会有所帮助:http: //en.wikipedia.org/wiki/Clone_(Java_method)
An Excerpt from the post:
帖子摘录:
Another disadvantage is that one often cannot access the clone() method on an abstract type. Most interfaces and abstract classes in Java do not specify a public clone() method. As a result, often the only way to use the clone() method is if you know the actual class of an object; which is contrary to the abstraction principle of using the most generic type possible. For example, if one has a List reference in Java, one cannot invoke clone() on that reference because List specifies no public clone() method. Actual implementations of List like ArrayList and LinkedList all generally have clone() methods themselves, but it is inconvenient and bad abstraction to carry around the actual class type of an object.
另一个缺点是通常无法访问抽象类型的 clone() 方法。Java 中的大多数接口和抽象类都没有指定公共 clone() 方法。因此,通常使用 clone() 方法的唯一方法是您知道对象的实际类;这与尽可能使用最通用类型的抽象原则背道而驰。例如,如果在 Java 中有一个 List 引用,则不能对该引用调用 clone(),因为 List 未指定公共 clone() 方法。ArrayList 和 LinkedList 等 List 的实际实现通常都有 clone() 方法本身,但是携带对象的实际类类型不方便且抽象不好。
回答by Itay Maman
Java's cloning mechanism is somewhat awkward. In order to be able to clone itself the class must do two things. First it must implement Clonable. Second it must override clone() and make it public.
Java 的克隆机制有点笨拙。为了能够克隆自己,类必须做两件事。首先它必须实现可克隆。其次,它必须覆盖 clone() 并将其公开。
In your example, you overrode clone() but you are invoking clone() not on the Employee class but rather on the Object.class() where clone() is only protected.
在您的示例中,您覆盖了 clone() 但您不是在 Employee 类上调用 clone() ,而是在仅受保护的 Object.class() 上调用 clone() 。
回答by Gábor Hargitai
You should simply write
你应该简单地写
return super.clone();
in your clone method and implement the Clonable interface.
在您的 clone 方法中并实现 Clonable 接口。
回答by Gareth Davis
Mister Bloch of Effective Java has some interesting words to say on the use of clone
.
Effective Java 的 Bloch 先生对clone
.
http://www.artima.com/intv/bloch13.html
http://www.artima.com/intv/bloch13.html
Generally the current thinking is to avoid the use of clone as it is error prone and greatly misunderstood, implementing copy constructor is an alternative strategy or using a brute force approach of deep copying the object using serialisation.
通常,当前的想法是避免使用克隆,因为它容易出错且容易被误解,实现复制构造函数是一种替代策略,或者使用使用序列化深度复制对象的蛮力方法。
回答by Mihai Toader
Basically in order to have a properly cloneable object is enough to have a public clone() method implemented in that class.
基本上,为了拥有一个可正确克隆的对象,在该类中实现公共 clone() 方法就足够了。
The Cloneable interface is a marker
interface used to signal to the VM that it's safe to implement the default protected clone() method as a field by field copy.
Cloneable 接口是一个marker
接口,用于向 VM 发出信号,表明将默认受保护的 clone() 方法实现为一个字段一个字段的副本是安全的。
In order to properly implement the clone method for a class you should do declare a public method clone like this().
为了正确实现类的 clone 方法,您应该声明一个像 this() 这样的公共方法 clone。
public Object clone() {
return super.clone();
}
A good working implementationk will create a new object and properly assign the fields as the business logic reaquires:
一个好的工作实现k将创建一个新对象并根据业务逻辑要求正确分配字段:
public Object clone() {
CurrentClass newObject = new CurrentClass();
newObject.field1 = this.field1; // for simple types: int, long, etc
newObject.referenceField = this.referenceField.clone(); // for agregate objects or references.
return newObject;
}
The conclusion: declare a public clone method. If you want to have the default implementation as a field by field copy call super and mark the class as Cloneable If you want only custom cloning you can ignore the Cloneable mark.
结论:声明一个公共克隆方法。如果您希望将默认实现作为字段复制调用 super 并将类标记为 Cloneable 如果您只想自定义克隆,则可以忽略 Cloneable 标记。
回答by Steve Kuo
The standard pattern for making a class cloneable is:
使类可克隆的标准模式是:
- Implement
Cloneable
- Override the
clone()
method and make it public - In
clone()
callsuper.clone()
and then copy any mutable object's state
- 实施
Cloneable
- 覆盖该
clone()
方法并使其公开 - 在
clone()
调用中super.clone()
然后复制任何可变对象的状态
You should notcreate a new object using new
. The proper way is to call super.clone()
for a new instance. Object
's clone()
is special and will create a new copy of the object and copy its primitive fields and references.
你应该不使用创建新的对象new
。正确的方法是调用super.clone()
一个新实例。Object
'sclone()
是特殊的,它将创建对象的新副本并复制其原始字段和引用。
For example:
例如:
public class Person implements Cloneable {
protected String name;
// Note that overridden clone is public
public Object clone() {
Person clone = (Person)super.clone();
// No need to copy name as the reference will be
// copied by Object's clone and String is immutable
return clone;
}
}
public class Employee extends Person {
protected int id;
protected java.awt.Point location;
public Object clone() {
Employee clone = (Employee )super.clone();
// No need to copy id as Object's clone has already copied it
// Need to clone location as Point is mutable and could change
clone.location = location.clone();
return clone;
}
}
回答by Cojones
I think the current green answer is bad, why you might ask?
我认为目前的绿色答案很糟糕,你为什么要问?
- It adds a lot of code
- It requires you to list all fields to be copied and do this
- This will not work for Lists when using clone() (This is what clone() for HashMap says: Returns a shallow copy of this HashMap instance: the keys and valuesthemselves are not cloned.) so you end up doing it manually (this makes me cry)
- 它添加了很多代码
- 它要求您列出要复制的所有字段并执行此操作
- 当使用 clone() 时,这对 Lists 不起作用(这就是 HashMap 的 clone() 所说的:返回此 HashMap 实例的浅拷贝:键和值本身没有被克隆。)所以你最终手动完成(这使得我哭了)
Oh and by the way serialization is also bad, you might have to add Serializable all over the place (this also makes me cry).
哦,顺便说一句,序列化也很糟糕,你可能不得不到处添加 Serializable (这也让我哭了)。
So what is the solution:
那么解决方法是什么:
Java Deep-Cloning library The cloning libraryis a small, open source (apache licence) java library which deep-clones objects. The objects don't have to implement the Cloneable interface. Effectivelly, this library can clone ANY java objects. It can be used i.e. in cache implementations if you don't want the cached object to be modified or whenever you want to create a deep copy of objects.
Java 深度克隆库 克隆库是一个小型的开源(Apache 许可)java 库,它可以深度克隆对象。这些对象不必实现 Cloneable 接口。实际上,这个库可以克隆任何 java 对象。如果您不希望缓存对象被修改,或者您想创建对象的深层副本,则可以在缓存实现中使用它。
Cloner cloner=new Cloner();
XX clone = cloner.deepClone(someObjectOfTypeXX);
Check it out at http://code.google.com/p/cloning/