我读了很多有关Object类中的clone()方法和Cloneable接口的线程,但是没有找到一个合理的答案来回答我的问题。
简而言之:
我发现Object类有一个名为clone()的方法,可以“神奇地”复制你的对象。但是,如果不实现Cloneable接口,则无法使用该方法,因为该接口允许Object使用clone()方法。那么为什么要这样做呢?为什么不应该从一开始就使每个对象都能够被克隆呢?
我读了很多有关Object类中的clone()方法和Cloneable接口的线程,但是没有找到一个合理的答案来回答我的问题。
简而言之:
我发现Object类有一个名为clone()的方法,可以“神奇地”复制你的对象。但是,如果不实现Cloneable接口,则无法使用该方法,因为该接口允许Object使用clone()方法。那么为什么要这样做呢?为什么不应该从一开始就使每个对象都能够被克隆呢?
对于一些可变数据,实现Cloneable是有意义的。
但对于以下情况则没有意义:
某些编码风格建议尽量减少新的可变数据对象。 Cloneable并不适用于所有情况,如果您使所有对象都可克隆,则无法干净地关闭它。
注意:有许多项目在任何地方都避免使用Cloneable。
clone
可能只会返回相同的对象,这并没有什么问题。克隆的唯一根本问题(但是很大)出现在一个对象封装了某个对象或实体的可变状态并且还封装了该对象的标识时。当克隆单个对象时,克隆体可以封装原始状态的分离副本,也可以维护用于封装原始状态的对象的标识,但不能同时具备两者。 - supercatclone
实现为简单的return this
,那么对于值集合和引用集合的分离类型是有意义的(值应该实现cloneable
,而引用的克隆方法则不会被使用)。为了真正使其工作,应该有一个 cloneableObject
具有受保护的“magic” memberwiseClone
方法,它将始终工作,而不是在对象中具有可能无法工作的clone
方法;公共clone方法的支持将独立于从cloneableObject
派生。 - supercat如果每个对象(包括用户定义类的对象)都可以通过使用clone
方法进行克隆,那么可能会导致意外改变被克隆的原始对象,因为clone
提供了原始对象的浅拷贝。例如:
class MyClass
{
private int val;
public void setVal(int i)
{
this.val = i;
}
public int getVal()
{
return this.val;
}
public static void main(String st[]) throws Exception
{
ArrayList<MyClass> ar = new ArrayList<MyClass>();
MyClass mc = new MyClass();
mc.setVal(50);
ar.add(mc);
ArrayList<MyClass> copy =(ArrayList) ar.clone();//Since ArrayList is cloneable
copy.get(0).setVal(10);
System.out.print(ar.get(0).getVal());//it shows 10 instead of 50!!
}
}
克隆意味着创建对象的新副本,并且不像赋值运算符那样共享内存位置。
示例
MyObject obj1 = new MyObject();
obj2 = obj1;
在这种情况下,如果您对obj1进行任何更改,则会反映在obj2中,反之亦然,因为obj2保存了obj1的内存位置。
但是,如果您不希望在obj1中看到对obj2所做的更改,或者不希望在obj2中看到对obj1所做的任何更改,则可以执行克隆操作。在这种情况下,两个对象将具有不同的内存位置。