[关闭]
@Beeder 2017-07-06T15:21:32.000000Z 字数 2125 阅读 509

深入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. if(this == obj){
  4. return true;
  5. }
  6. if(obj instanceof Dog){
  7. Dog anotherDog = (Dog)obj;
  8. if(this.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. if(this == 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. if(this == obj){
  4. return true;
  5. }
  6. if(obj instanceof Dog){
  7. return name.equals(((Dog)obj).getName());
  8. }
  9. return false;
  10. }

以后记住在浅拷贝的时候String引用还是指向原来的内存空间。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注