重新学习了一遍java中的克隆,感觉原来学的太肤浅了,好多特性没有了解到。重新总结一遍:1.java中的克隆对应设计模式中的prototype pattern。2.如果一个对象想要被克隆,需要实现java.lang.Cloneable接口,这个接口和java.io.Serializable接口相似,都是不包含任何方法的接口,用来进行标志。3.实现Cloneable接口后,需要覆盖Object类中的clone方法,是Object中的一个native方法,需要注意的是Object本身并没有实现Cloneable接口,所以不能对Object对象进行clone。4.克隆分为shallow copy和deep copy
1、浅复制(浅克隆) 概念:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。 方法:类implements Cloneable,然后重写clone()方法,在clone()方法中调用super.clone()即可,没有其他操作了
2、深复制(深克隆) 概念:被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍 方法: (1)类implements Cloneable,然后重写clone()方法,在clone()方法中调用super.clone(),然后还要对引用型变量所指的对象进行克隆。 (2)序列化:将该对象写出到对象输出流,那么用对象输入流读回的对象就是原对象的一个深度克隆5.java文档上推荐的克隆的实现标准The general intent is that, for any object
x, the expression:
x.clone() != x
will be true, and that the expression:
x.clone().getClass() == x.getClass()
will be
true, but these are not absolute requirements. While it is typically the case that:
x.clone().equals(x)
will be
true, this is not an absolute requirement.
1) 克隆新生成了一个对象,所以引用不同。2) 克隆的对象与原来的对象是相同的类型,所以getClass应该相同。3) 按照java的规范,在调用一个对象的equals方法前,这个对象应该已经重写了equals方法,这样比较的不仅仅是引用,所以这里指的是两个对象的信息是否相同,克隆出来的对象信息当然相同,所以这里应该为true。
6.记一下今天写的测试代码重写Dog类的equals方法,仿照String类写的
- @Override
- public boolean equals(Object obj) {
- if(this == obj){
- return true;
- }
- if(obj instanceof Dog){
- Dog anotherDog = (Dog)obj;
- if(this.getName() == anotherDog.getName()){
- return true;
- }
- }
- return false;
- }
重写Dog类的clone方法
- @Override
- public Dog clone() {
- Dog dog = null;
- try {
- dog = (Dog) super.clone();
- dog.setClothes(getClothes().clone());//深克隆时把复制的对象所引用的对象也要clone
- } catch (CloneNotSupportedException exception) {
- exception.printStackTrace();
- }
- return dog;
- }
PS:要想知道clone真正的用武之地还得在实际中。又看了一眼Integer的toString方法,Dog的equals方法还可以优化,改为
- @Override
- public boolean equals(Object obj) {
- if(this == obj){
- return true;
- }
- if(obj instanceof Dog){
- return name == ((Dog)obj).getName();
- }
- return false;
- }
三行和一行是等价的......
写完了又发现这篇文章有2个严重的错误,弄巧成拙最后测试结果对了,不在文章上直接改,为了能牢记错误~。1.String name是引用,所以在浅克隆的时候name仅仅是复制的引用。2.在equals方法中,比较两个String是用的==比较的,好久没有这种错误了。正好name复制的是引用,所以 == 还是返回的true。改正:
- @Override
- public boolean equals(Object obj) {
- if(this == obj){
- return true;
- }
- if(obj instanceof Dog){
- return name.equals(((Dog)obj).getName());
- }
- return false;
- }
以后记住在浅拷贝的时候String引用还是指向原来的内存空间。 String类型还有些不同,见 http://www.linuxidc.com/Linux/2011-10/44936.htm