Welcome 微信登录

首页 / 操作系统 / Linux / 深入Java克隆

重新学习了一遍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类写的
  1. @Override  
  2. public boolean equals(Object obj) {  
  3.     ifthis == obj){  
  4.         return true;  
  5.     }  
  6.     if(obj instanceof Dog){  
  7.         Dog anotherDog = (Dog)obj;  
  8.         ifthis.getName() == anotherDog.getName()){  
  9.             return true;  
  10.         }  
  11.     }  
  12.     return false;  
  13. }  
重写Dog类的clone方法
  1. @Override  
  2. public Dog clone() {  
  3.     Dog dog = null;  
  4.     try {  
  5.         dog = (Dog) super.clone();  
  6.         dog.setClothes(getClothes().clone());//深克隆时把复制的对象所引用的对象也要clone   
  7.     } catch (CloneNotSupportedException exception) {  
  8.         exception.printStackTrace();  
  9.     }  
  10.     return dog;  
  11. }  
PS:要想知道clone真正的用武之地还得在实际中。又看了一眼Integer的toString方法,Dog的equals方法还可以优化,改为
  1. @Override  
  2. public boolean equals(Object obj) {  
  3.     ifthis == obj){  
  4.         return true;  
  5.     }  
  6.     if(obj instanceof Dog){  
  7.         return name == ((Dog)obj).getName();  
  8.     }  
  9.     return false;  
  10. }  
三行和一行是等价的......
写完了又发现这篇文章有2个严重的错误,弄巧成拙最后测试结果对了,不在文章上直接改,为了能牢记错误~。1.String name是引用,所以在浅克隆的时候name仅仅是复制的引用。2.在equals方法中,比较两个String是用的==比较的,好久没有这种错误了。正好name复制的是引用,所以 == 还是返回的true。改正:
  1. @Override  
  2. public boolean equals(Object obj) {  
  3.     ifthis == obj){  
  4.         return true;  
  5.     }  
  6.     if(obj instanceof Dog){  
  7.         return name.equals(((Dog)obj).getName());  
  8.     }  
  9.     return false;  
  10. }  
以后记住在浅拷贝的时候String引用还是指向原来的内存空间。 String类型还有些不同,见 http://www.linuxidc.com/Linux/2011-10/44936.htm