clone小结
clone用途:有人使用clone做一个对象的存根。存根的一个使用比如发票开出之后,还需要一个一模一样的存根以供查询。另外,一个用途是客户端不关心创建的细节,使用构造方法创建就需要关心细节,知道每个参数的含义。而clone根本不关心。在创建出属性一模一样的实例后,客户端可以调整里面的某些属性值。一个简单的例子比如要给ABC三家公司发送主体相同,但是工作经历不同的简历。这时可以先clone三份出来,再分别针对每个公司的简历设置不同的工作经历。
一.clone的定义:
wiki:clone()
is a method in the Java programming language for object duplication. In Java, objects are manipulated through reference variables, and there is no operator for copying an object—the assignment operator duplicates the reference, not the object. The clone() method provides this missing functionality
二. 知识点:
1.了解clone的deep copy, shallow copy, 一定要清楚immutable object&mutable object。
immutable object的典型示例是String,实例化之后,content是不可变的。而与之对应的mutable object是StringBuffer,content是可变的。
2.Cloneable一般用于子类,而不是父类。表示 Object.clone() 方法可以合法地对该类实例进行按字段复制。Cloneable 接口实际上是个标识接口,没有任何接口方法。
子类声明实现Cloneable通常做法是重写Object.clone方法为public Subclass clone && not throw CloneNotSupportedException来供外部访问。
示例:
//方法的override会检查返回类型(可以是子类),参数,方法名是否一致。同时不能缩小修饰符,不能增加抛出异常。
@Override public PhoneNumber clone() { try { return (PhoneNumber) super.clone(); } catch(CloneNotSupportedException e) { throw new AssertionError(); // Can't happen } }
而@Override protected Object clone() throws CloneNotSupportedException一般用于父类。默认定义在Object,对所有域进行shallow copy,如果父类里面没有mutable object的属性,可以不复盖clone方法。使用默认的即可。如果有就需要复盖实现deep copy。
@Override protected Object clone() throws CloneNotSupportedException{ Object obj=super.clone();
//do some deep copy. return obj; }
3.对于一些包含了mutable object的object,deep copy的实现小心栈溢出。
在实现deep copy时,有人使用递归,正确的方式是应该多用迭代。当递归的内容很多的话,栈变量无法及时释放。具体可研究effective java示例。
4.assignment只是duplicate reference,指向的内存堆是一样的。如果需要duplicate object,就需要override clone方法并且deep copy。虽然java提供了默认的clone,但是effective java认为默认的clone是shallow copy,会误导调用者。
示例:http://stackoverflow.com/questions/6384826/clone-method-in-java
the clone() method and a simple assingment difference: clone不仅return object是新的reference,属性也是新的reference.而assignment只是object是reference,属性的 reference仍然一样。
三。clone小结
1. 为什么说effective java中的clone item是 ill-defined terms:
当object里面只是primitive value以及immutable object时,这时clone默认的shallow copy可以很好的工作。
shallow copy对于mutable object只会duplicates the reference, not the object。
所以当包含mutable object的属性时,会导致返回的object中的mutable object属性与原来的属性的reference指向的堆是一样的。从而导致这些mutable object不知何时会被别的类修改。
This is, of course, sometimes exactly the behavior that you need. In other cases, however, it can lead to frustrating and inexplicable errors, as the state of an object seems to change “behind your back”.
所以,当mutable object属性存在时,需要通过deep copy实现下面的效果:
2.实现的方式:mutable object需要serializable,利用unserializable实例化一个新的对象返回。
For example org.apache.commons.lang.SerializationUtils will have method for Deep clone using serialization(Source).
· org.apache.commons.lang.SerializationUtils.clone(Serializable object):Deep clone an Object using serialization.
3.实现的原理:http://javatechniques.com/blog/faster-deep-copies-of-java-objects/
4. 替代clone方法
除了上面讨论的deep copy的实现之外,尽量不要使用clone而使用copy constructors
clone is tricky to implement correctly.It's better to use Defensive copying, copy constructors or static factory methods.
Copy constructors provide an attractive alternative to the rather pathological clone method.
参考:http://stackoverflow.com/questions/6182565/java-deep-copy-shallow-copy-clone
4.1为什么不推荐使用clone
Josh Bloch in Effective Java also doesn't recommend to use clone () method.
There are several problems with this method:
1) If cloneable object have not only primitive type fields but also object fields then cloned object will receive just references to those objects but not real cloned objects. To avoid this all inner objects should be cloneable too.
2) If you make a subclass of cloneable class then it's cloneable too (even if you don't want). That's why you should override clone () method in a proper way to avoid possible problems.
3)First version of java was released rather fast. They made great work and numerous their decisions were very smart. But they also made a few mistakes, like java.util.Date class or clone () method. If it was added once to the API they can't ever change it
5. effective java中的clone摘要:
Object’s clone method is declared to throw CloneNotSupportedException, but overriding clone methods can omit this declaration. Public clone methods should omit it because methods that don’t throw checked exceptions are easier to use (Item 59). If a class that is designed for inheritance (Item 17) overrides clone, the overriding method should mimic the behavior of Object.clone: it should be declared protected, it should be declared to throw CloneNotSupportedException, and the class should not implement Cloneable. This gives subclasses the freedom to implement Cloneable or not, just as if they extended Object directly.
To recap, all classes that implement Cloneable should override clone with a public method whose return type is the class itself. This method should first call super.clone and then fix any fields that need to be fixed. Typically, this means copying any mutable objects that comprise the internal “deep structure” of the object being cloned, and replacing the clone’s references to these objects with references to the copies. While these internal copies can generally be made by calling clone recursively, this is not always the best approach. If the class contains only primitive fields or references to immutable objects, then it is probably the case that no fields need to be fixed