要克隆对象,我需要实现“cloneable”接口吗?因为我的类是一个jar文件(即API),所以无法编辑该类。我听说所有类都扩展了基本的Object类,并且这个Object类实现了Cloneable接口。这是否意味着我们可以直接克隆对象而不需要实现接口?如果是这样,在我的Eclipse中,我没有获得任何克隆对象的选项。有没有其他方法可以在不实现Cloneable接口的情况下克隆对象。请解释。
要克隆对象,我需要实现“cloneable”接口吗?因为我的类是一个jar文件(即API),所以无法编辑该类。我听说所有类都扩展了基本的Object类,并且这个Object类实现了Cloneable接口。这是否意味着我们可以直接克隆对象而不需要实现接口?如果是这样,在我的Eclipse中,我没有获得任何克隆对象的选项。有没有其他方法可以在不实现Cloneable接口的情况下克隆对象。请解释。
通常最好避免使用 clone(),因为难以正确地实现 (http://www.javapractices.com/topic/TopicAction.do?Id=71)。也许相关类有一个复制构造函数?
或者,如果它实现了 Serializable 或 Externalizable 接口,您可以通过将其写入字节流并重新读取来深层复制它。
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
Object deepCopy = ois.readObject();
(来源于http://www.jguru.com/faq/view.jsp?EID=20435)这种方法简单快捷,但并不美观…通常情况下我会把它作为最后的手段。
XYZ
的子类,则public XYZ(toCopy)
将无法工作。 - Steve Kuo有一个API可以在不实现Cloneable接口的情况下克隆对象。
试一试
https://github.com/kostaskougios/cloning
此外,您可以在此处找到有关克隆对象的更多详细信息。http://javatechniques.com/blog/faster-deep-copies-of-java-objects/
不一定需要实现Cloneable接口来克隆一个对象。 你可以在想要克隆的类中编写自己的clone方法。
尝试在一个没有实现Cloneable接口的类上调用clone方法会抛出CloneNotSupportedException异常,而且Object类也没有实现Cloneable接口。
这里是Object类的clone方法的javadoc:
CloneNotSupportedException if the object's class does not
* support the <code>Cloneable</code> interface. Subclasses
* that override the <code>clone</code> method can also
* throw this exception to indicate that an instance cannot
* be cloned.
同时,Object#clone方法是受保护的,因此您需要在您的类中实现clone方法并将其设置为public,以便可以访问您的类对象的类调用它。一个很好的例子是ArrayList中实现clone的方式。
ArrayList像下面这样实现了cloneable: public class ArrayList extends AbstractList implements List, RandomAccess, Cloneable, java.io.Serializable
然后实现了clone方法:
/**
* Returns a shallow copy of this <tt>ArrayList</tt> instance. (The
* elements themselves are not copied.)
*
* @return a clone of this <tt>ArrayList</tt> instance
*/
public Object clone() {
try {
ArrayList<E> v = (ArrayList<E>) super.clone();
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
}
clone()
。谷歌搜索的第一个链接是:http://www.javapractices.com/topic/TopicAction.do?Id=12 - clstrfsckObject类中的clone()方法是受保护的,这意味着所有类都将继承它并带有受保护的访问修饰符,因此如果您尝试在未克隆的情况下在该类之外访问它,则不会看到它,而且如果您尝试在未实现Cloneable接口的情况下调用它,它将抛出CloneNotSupportedException异常。
如果您想要创建克隆行为的方式,需要在您的类中编写一个新方法,然后创建该方法中所有字段的副本,这基本上就像创建对象现有状态的新副本。
public class TestCloneable {
private String name = null;
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the name
*/
public String getName() {
return name;
}
public TestCloneable createCopy(){
TestCloneable testCloneable = new TestCloneable();
testCloneable.setName(this.getName());
return testCloneable;
}
}
您可以使用Unsafe来创建一个对象实例,然后通过Java反射将值复制到新实例中。但是正如Unsafe的名称所示,这并不是一个真正好的解决方案。
public static Unsafe unsafe;
static {
Field f;
try {
f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
unsafe = (Unsafe) f.get(null);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
public static <T> T clone(T object) throws InstantiationException {
T instance = (T) unsafe.allocateInstance(object.getClass());
copyInto(object,instance);
return instance;
}
public static void copyInto(Object source,Object destination){
Class<?> clazz = source.getClass();
while (!clazz.equals(Object.class)) {
for (Field field : clazz.getDeclaredFields()) {
field.setAccessible(true);
try {
field.set(destination, field.get(source));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
clazz = clazz.getSuperclass();
}
}