Clonable接口
我们船舰了一个人的对象,想要克隆一个一模一样的对象,可以用到object类里面的克隆方法
object不是所有类的父类吗?那为什么用person1点不出这个方法呢?可以看一下源码
这是Object类里面的clone方法的声明,native说明这是本地方法,底层是由c/c++实现的。注意,它的访问权限是protected,所以再不同包中的子类只可以用super来引用,但super又不能静态方法中使用,所以我们只能再Person类里面重写一个方法,如下:
但还是报错,注意throws CloneNotSupportedException表示克隆不支持异常,语法规定,我们需要在main方法后面也加上这一句,同时,clone方法的返回值是Object类型,但在main方法中我们用了它的子类来接收,这是向下转型,必须要用括号强转,如下:
但还是报错,这就是 CloneNotSupportedException,即不支持克隆,那么这时,Clonable接口就起作用了,我们需要让那个被克隆的类去实现Clonable接口,如下:
空接口/标记接口
我们再看一下接口的源码:
发现里面没有任何抽象方法,这就是一个空接口或者叫标记接口,表示该类可以被拿去克隆
将上面的错误全部修正后,person1就可以被克隆了
深拷贝与浅拷贝
现在,我们再在person类里面加一个成员变量money,它是Money类的
class Money{public double m=29.9;}
class Person implements Cloneable{public String name;public int age;public Money money=new Money();public Person(String name, int age) {this.name = name;this.age = age;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}
public class Test {public static void main(String[] args)throws CloneNotSupportedException {Person person1=new Person("张三",20);Person person2=(Person)person1.clone();System.out.println("person1:"+person1.money.m);System.out.println("person1:"+person2.money.m);System.out.println("==========");person1.money.m=99.9;System.out.println("person1:"+person1.money.m);System.out.println("person1:"+person2.money.m);}
}
如上,那输出的结果是什么?
浅拷贝
按理说,即使person2是克隆出来的,但它也是一个独立的个体,应该不会受person1的影响,可却出现了上面的现象,实际上,在拷贝money时,由于money是个引用类型,它的值是所指对象的地址,在拷贝时,就将person1的money的值直接给到了person2的money,导致两个money都指向了同一个对象,而不是我们想看到的不是同一个对象而只是有一样的值罢了。
这种对于money的拷贝就是浅拷贝
深拷贝
那如何进行深拷贝?其实就是再给person2的money另外开辟一块空间,然后再将person1的money所指对象的值拷贝到person2的money所指对象。既然要克隆money,那么就要让money也支持克隆,如下
第二张图的第二行代码是刚刚的浅拷贝,在它的基础上再将money也拷贝一份,就能实现真正意义上的一式两份,也就是深拷贝。那么我们如何将二三行代码合在一起?先看一下重写的克隆方法:
这个方法是放在哪个类就克隆哪个类,由于在person类里面重写的clone方法仅支持person的克隆,所以我们可以修改这个克隆方法使他还可以将内部的money也克隆一份,而不仅仅是克隆其表面的值,如下:
可是,这个代码有很大的问题,当我们用this.clone时,就会出现死循环,一i那位这是自己调用了自己,所以应该修改为用Object类的clone方法,即用到super,如下:
这时修改1的值就不会影响2了
最终代码就是
class Money implements Cloneable{@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}public double m=29.9;}
class Person implements Cloneable{public String name;public int age;public Money money=new Money();public Person(String name, int age) {this.name = name;this.age = age;}@Overrideprotected Object clone() throws CloneNotSupportedException {Person tmp=(Person) super.clone();Money money=(Money) this.money.clone();tmp.money=money;return tmp;}
}
public class Test {public static void main(String[] args)throws CloneNotSupportedException {Person person1=new Person("张三",20);Person person2=(Person)person1.clone();//person2.money= (Money) person1.money.clone();System.out.println("person1:"+person1.money.m);System.out.println("person2:"+person2.money.m);System.out.println("==========");person1.money.m=99.9;System.out.println("person1:"+person1.money.m);System.out.println("person2:"+person2.money.m);