jus*_*rld 15 java abstract-class clone
在这个问题,这个帖子解释了如何通过使用保护的拷贝构造函数来克隆与最终字段的对象.
但是,假设我们有:
public abstract class Person implements Cloneable
{
private final Brain brain; // brain is final since I do not want
// any transplant on it once created!
private int age;
public Person(Brain aBrain, int theAge)
{
brain = aBrain;
age = theAge;
}
protected Person(Person another)
{
Brain refBrain = null;
try
{
refBrain = (Brain) another.brain.clone();
// You can set the brain in the constructor
}
catch(CloneNotSupportedException e) {}
brain = refBrain;
age = another.age;
}
public String toString()
{
return "This is person with " + brain;
// Not meant to sound rude as it reads!
}
public Object clone()
{
return new Person(this);
}
public abstract void Think(); //!!!!
…
}
Run Code Online (Sandbox Code Playgroud)
返回错误,因为我们无法实例化抽象类.我们怎么解决这个问题?
Era*_*ran 19
您不在clone()抽象类中实现该方法,只在具体的子类中实现.
public class SomeConcretePerson extends Person
{
public SomeConcretePerson (SomeConcretePerson another)
{
super (another); // this will invoke Person's copy constructor
}
public Object clone()
{
return new SomeConcretePerson(this);
}
}
Run Code Online (Sandbox Code Playgroud)
在极少数情况下,我们可能无法使用复制构造函数技术并且必须使用该clone()方法.对于这些情况,值得知道Java提供了解决final现场问题的方法:
public abstract class Person implements Cloneable {
private final Brain brain;
private int age;
public Person(Brain aBrain, int theAge) {
brain = aBrain;
age = theAge;
}
@Override public String toString() {
return "This is person with " + brain;
// Not meant to sound rude as it reads!
}
@Override public Person clone() {
try {
Person clone = (Person)super.clone();
Field brainField=Person.class.getDeclaredField("brain");
brainField.setAccessible(true);
brainField.set(clone, brain.clone());
return clone;
} catch (CloneNotSupportedException|ReflectiveOperationException ex) {
throw new AssertionError(ex);
}
}
public abstract void think();
…
}
Run Code Online (Sandbox Code Playgroud)
final为完全这样的用例创建了覆盖限制的可能性,克隆或反序列化对象,其中不会调用构造函数.在Java语言规范,§17.5.3.final字段的后续修改状态:
在某些情况下,例如反序列化,系统将需要
final在构造之后更改对象的字段.final可以通过反射和其他依赖于实现的方式来更改字段.它具有合理语义的唯一模式是构造对象然后final更新对象字段的模式.对象不应该对其他线程可见,也不应该final读取字段,直到final完成对象字段的所有更新.
这正是示例的工作原理,final在克隆构建之后,克隆暴露给任何人之前设置字段,而不是读取任何字段.
如上所述,需要这种情况的情况很少见.只要您可以实现基于复制构造函数的解决方案,请使用它.