我想知道以下几点:
Cloneable意味着通过实现Cloneable接口,我们可以拥有对象的克隆或副本。这样做有什么好处和缺点?发布于 2010-11-02 20:50:55
令人遗憾的是,Cloneable本身只是一个标记-接口,也就是说:它不定义克隆()方法。
所做的是更改受保护的Object.clone()方法的行为,该方法将为不实现Cloneable的类抛出一个CloneNotSupportedException,并对这样做的类执行一个按成员划分的浅拷贝。
即使这是您要寻找的行为,您仍然需要实现自己的克隆()方法,以便将其公之于众。
在实现您自己的克隆()时,我们的想法是从super.clone()创建的对象开始,该对象保证属于正确的类,然后执行任何额外的字段填充,以防浅层副本不是您想要的。从克隆()调用构造函数是有问题的,因为如果子类想要添加自己的额外可复制逻辑,则会破坏继承;如果要调用super.clone(),则在本例中将得到错误类的对象。
但是,这种方法绕过了在构造函数中定义的任何逻辑,这可能会产生问题。
另一个问题是,任何忘记覆盖克隆()的子类都将自动继承默认的浅拷贝,在发生可变状态(现在将在源和副本之间共享)时,这可能不是您想要的。
由于这些原因,大多数开发人员不会使用Cloneable,而只是实现一个复制构造函数。
欲了解更多信息和克隆的潜在缺陷,我强烈推荐由约书亚·布洛赫撰写的“有效Java”一书
发布于 2010-11-02 20:45:26
。
所以,明智地使用克隆。它并没有给你足够的好处,相比你需要努力去做好每件事。
发布于 2014-02-15 22:13:48
克隆是一种基本的编程模式。事实上,Java在许多方面可能没有很好地实现它,这一点丝毫没有减少克隆的必要性。而且,实现克隆是很容易的,不管你希望它如何工作,浅层,深,混合,什么都行。您甚至可以为函数使用名称克隆,如果您愿意,也不能实现Cloneable。
假设我有A、B和C类,其中B和C是从A派生的,如果我有一个A类型的对象列表,如下所示:
ArrayList<A> list1;现在,这个列表可以包含A、B或C类型的对象,您不知道这些对象是什么类型。所以,你不能像这样复制列表:
ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
list2.add(new A(a));
}如果对象实际上是B或C类型的,则不会得到正确的副本。如果A是抽象的呢?现在,有人建议这样做:
ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
if(a instanceof A) {
list2.add(new A(a));
} else if(a instanceof B) {
list2.add(new B(a));
} else if(a instanceof C) {
list2.add(new C(a));
}
}这是个非常非常糟糕的主意。如果您添加了一个新的派生类型怎么办?如果B或C在另一个包中,而您在这个类中没有访问它们的权限,该怎么办?
你想做的是:
ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
list2.add(a.clone());
}许多人已经指出了为什么克隆的基本Java实现是有问题的。但是,它很容易克服这种方式:
在A班:
public A clone() {
return new A(this);
}在B班:
@Override
public B clone() {
return new B(this);
}在C班:
@Override
public C clone() {
return new C(this):
}我没有实现Cloneable,只是使用相同的函数名。如果你不喜欢,就说点别的吧。
https://stackoverflow.com/questions/4081858
复制相似问题