深拷贝浅拷贝
好久没写东西了,今天来聊聊深浅拷贝这两个东西。
深拷贝浅拷贝,其实我们也叫他深克隆浅克隆,
故名思议就是跟Object基类的clone()有关。
我们先定义一下材料类:
package test;
/**
* @author lujw E-mail: aaa@qq.com
* @date 创建时间:2017年12月11日 下午1:28:33
*/
public class Material {
private String id = "1";
public String getId() {
return id;
}
}
package test;
/**
* @author lujw E-mail: aaa@qq.com
* @date 创建时间:2017年11月16日 下午1:44:30
*/
public class temp1 {
public static void main(String[] args) {
Material material = new Material();
Material materialTemp = material;
System.out.println(material.toString() + "\n" + materialTemp.toString());
}
}
那么,待会出来的结果会是什么呢?相信你们也是知道的,打印了这两个对象实例的地址:
aaa@qq.com
aaa@qq.com
一样的,其实不难知道,这种操作只能是把两个引用引导到堆里面同一块地方。
那么这么样才能"制造出长得一样的实例"呢?这是Object中的clone()就出现了。
要用clone()方法就必须继承Cloneable接口,那为什么clone()是在Object而不是在Cloneable下呢?
其实大家都知道,基本所有的类都基本默认继承了Object,同时clone也应该是所有类的一个基本属性,就写在了Object之下,
如果你没有接上Cloneable这个接口直接用clone()的话,会报CloneNotSupportedException这个异常,这个接口说实在的就是个标志,就是跟你说我是可以克隆的。
-------------------------扯远了----------------------------
那我们接上Cloneable看看
package test;
/**
* @author lujw E-mail: aaa@qq.com
* @date 创建时间:2017年12月11日 下午1:28:33
*/
public class Material implements Cloneable{
private String id = "1";
public String getId() {
return id;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
这里接上Cloneable同时还是重写Object的clone(),不然不给用。
然后我们再改我们的测试main:
package test;
/**
* @author lujw E-mail: aaa@qq.com
* @date 创建时间:2017年11月16日 下午1:44:30
*/
public class temp1 {
public static void main(String[] args) {
Material material = new Material();
Material materialTemp = null;
try {
materialTemp = (Material) material.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
System.out.println(material.toString() + "\n" + materialTemp.toString());
}
}
这个时候打印出来的是这样的:
aaa@qq.com
aaa@qq.com
这样就实现了对象实例化的克隆。
那有人就问了:废话说得这么多,要讲深克隆浅克隆了吗?
这位兄弟,别急吗,我这就讲,你先把刀从我脖子移开行吗?
浅拷贝:
上面的基础例子我们知道了,那真就是拷贝完成了吗
那我们再来测试一下:
package test;
/**
* @author lujw E-mail: aaa@qq.com
* @date 创建时间:2017年11月16日 下午1:44:30
*/
public class temp1 {
public static void main(String[] args) {
Material material = new Material();
Material materialTemp = null;
try {
materialTemp = (Material) material.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
System.out.println(material.toString() + "\n" + materialTemp.toString());
System.out.println(material.getId().hashCode() + "\n" + materialTemp.getId().hashCode()); //基本类型咱们用hashCode代替。
}
}
那你觉得现在结果是怎么样的呢?
答案是这样的:
aaa@qq.com
aaa@qq.com
49
49
材料类(Material)确实是进行了克隆,但是,材料类的里面属性还是在内存的同一块地方啊
这就是浅拷贝了
浅拷贝就是只是克隆了表面而已,但是里面的对象实例内存的指向就还是一样,这个时候我们再来看看我们的深拷贝。
深拷贝:
我们在材料类再加个东西
我们先定义金属类(Metal)
package test;
/**
* @author lujw E-mail: aaa@qq.com
* @date 创建时间:2017年12月12日 下午12:51:39
*/
public class Metal{
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
然后在材料类中加上去这个金属类:
package test;
/**
* @author lujw E-mail: aaa@qq.com
* @date 创建时间:2017年12月11日 下午1:28:33
*/
public class Material implements Cloneable{
private String id = "1";
private Metal metal = new Metal();
public String getId() {
return id;
}
public Metal getMetal(){
return metal;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
这个时候打印这个
System.out.println(material.getMetal().toString() + "\n" + materialTemp.getMetal().toString());
结果肯定是一样的:
aaa@qq.com
aaa@qq.com
深拷贝的主要点就在这了:
这个时候我们要先给金属类接上Cloneable并加上clone的属性
package test;
/**
* @author lujw E-mail: aaa@qq.com
* @date 创建时间:2017年12月12日 下午12:51:39
*/
public class Metal implements Cloneable{
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
@Override
protected Object clone() throws CloneNotSupportedException {
Material newMaterial = (Material) super.clone();
newMaterial.metal = (Metal) metal.clone();
return newMaterial;
}
再次测试:
System.out.println(material.toString() + "\n" + materialTemp.toString());
System.out.println(material.getMetal().toString() + "\n" + materialTemp.getMetal().toString());
结果是这样的:
aaa@qq.com
aaa@qq.com
aaa@qq.com
aaa@qq.com
当然,深拷贝这个东西是没有个绝对的,毕竟每个业务对象是不一样的,每个对象里面的属性是各不相同,
例子我刚刚的材料类(Material),里面有金属类(Metal),那金属类(Metal)之后还有可能是有黄金类(Gold)。。。
所以,复杂的业务往往比较难以全面考虑,全面考虑也是没什么用的,只要紧跟着业务走,就够了,没必要搞什么彻底深拷贝。
----------------------------------------分割线--------------------------------------------------
利用午休写的,写得烂有问题尽管在低下批评。
反正我也不会改。