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;
}
@Override
protected 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{
@Override
protected 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;
}
@Override
protected 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);