今天来看提示十三:谨慎地覆盖clone。
我们经常遇到想要克隆一个对象的需求,Object类中存在一个protected方法clone(),这是一个本地方法,会返回该对象的逐个属性的拷贝。这是一个浅拷贝,即如果这个类中某个属性是一个复杂对象,那么返回的克隆对象中的该属性只是一个引用而非新的对象。我猜测这里的clone是基于反射来做的,可惜没有什么好方法来证实,或许可以编译以后再反编译打开看看。
书中Object的规范中clone方法有这样几条通用的约定(不是必须的要求):
x.clone() != x
x.clone().getClass() == x.getClass()
x.clone().equals(x)
另外还有这样几条有用的信息:
- immutable的类不应该提供
clone
方法。 - 公有的
clone
方法应该省略throws,为了继承而设计的类不应该实现Cloneable
。 - 如果需要线程安全的
Cloneable
方法,需要使用synchronized
。 - 对象复制更好的方法是提供一个复制构造方法或复制工厂。 复制构造方法接受参数,其类型为包含此构造方法的类。
// Copy constructor public Yum(Yum yum) { ... };
// Copy factory public static Yum newInstance(Yum yum) { ... };
我们系统中也使用了cloneable接口,但是一般都是一些简单的vo,那么直接实现接口,不需要覆盖clone方法也能满足要求,但是考虑到proctected的方法的使用范围,一般都会重写clone方法,把方法的范围改成public同时可以返回更为具体的类,而非Object。但是面对复杂对象,需要深拷贝的情况下,cloneable接口就感觉有一些力不从心了。当然我们也可以递归调用clone方法来实现,但是目前我们更普遍的做法是json来序列号在反序列化来简单实现这一需要,当然更复杂的情况需要手工处理更多的信息就不讨论了。

网友评论