java 深克隆 浅克隆_浅谈Java中的深克隆和浅克隆(阿里面试)

在最近的秋招中,阿里和多益网络都问到了这个问题,虽然很简单,但是我还是想总结一下,感兴趣的可以看一下我的个人博客网站(Spring+MyBatis+redis+nginx+mysql)(适合菜鸟),最近会抽空把最近面试遇到的问题总结一下。

本文针对问题:深克隆和浅克隆的区别和实现方式?(阿里电面,多益网络的选择题)

Talk is cheap

最近不止一次遇见深浅克隆(深复制,浅复制)的问题,除了印象中有个clone方法外一脸懵逼!!!克隆(复制)在Java中是一种常见的操作,目的是快速获取一个对象副本。克隆分为深克隆和浅克隆。

浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。

深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。

总之深浅克隆都会在堆中新分配一块区域,区别在于对象属性引用的对象是否需要进行克隆(递归性的)。

Show you my picture

pos:当前对象的地址;

son:son属性所指向的地址;

name:对象的name属性。

7bb0dd801375bef1aa4327541d511d05.png

Show you my code

case1:

public class Son implements Serializable , Cloneable{

private String name;

private Son son;

public Son() {

super();

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public Son getSon() {

return son;

}

public void setSon(Son son) {

this.son = son;

}

@Override

public String toString() {

return super.toString();

}

@Override

protected Object clone() throws CloneNotSupportedException {

return super.clone();

}

}

测试

public static void main(String[] args) throws Exception{

// 创建父亲(LiLiu),儿子(LiWu),孙子(LiLiu)并关联

Son father = new Son();

father.setName("LiSi");

Son son = new Son();

son.setName("LiWu");

Son grandSon = new Son();

grandSon.setName("LiLiu");

father.setSon(son);

son.setSon(grandSon);

// 调用clone方法

Son fatherCopy = (Son) father.clone();

boolean flag1 = fatherCopy==father;

boolean flag2 = fatherCopy.getSon() == son;

boolean flag3 = fatherCopy.getSon().getSon() == grandSon;

// 比较克隆后的地址

System.out.println(flag1);// false

System.out.println(flag2);// true

System.out.println(flag3);// true

// 比较Name

flag1= fatherCopy.getName()==father.getName();

flag2 = fatherCopy.getSon().getName() == son.getName();

flag3 = fatherCopy.getSon().getSon().getName() == grandSon.getName();

System.out.println(flag1);// true

System.out.println(flag2);// true

System.out.println(flag3);// true

//将对象写到流里

ByteArrayOutputStream byteOut=new ByteArrayOutputStream();

ObjectOutputStream objOut=new ObjectOutputStream(byteOut);

objOut.writeObject(father);

//从流里读出来

ByteArrayInputStream byteIn=new ByteArrayInputStream(byteOut.toByteArray());

ObjectInputStream objInput=new ObjectInputStream(byteIn);

fatherCopy = (Son) objInput.readObject();

flag1= fatherCopy==father;

flag2 = fatherCopy.getSon() == son;

flag3 = fatherCopy.getSon().getSon() == grandSon;

System.out.println(flag1);// false

System.out.println(flag2);// false

System.out.println(flag3);// false

// 比较Name

flag1= fatherCopy.getName()==father.getName();

flag2 = fatherCopy.getSon().getName() == son.getName();

flag3 = fatherCopy.getSon().getSon().getName() == grandSon.getName();

System.out.println(flag1);// false

System.out.println(flag2);// false

System.out.println(flag3);// false

}

从上文代码及运行结果不难看出,如果对象实现Cloneable并重写clone方法不进行任何操作时,调用clone是进行的浅克隆。而使用对象流将对象写入流然后再读出是进行的深克隆。

思考:既然实现Cloneable接口并重写clone接口只能进行浅克隆。但是如果类的引用类型属性(以及属性的引用类型属性)都进行浅克隆,直到没有引用类型属性或者引用类型属性为null时,整体上就形成了深克隆。既对象的引用类型属性和属性的应用类型属性都实现Coloneable,重写clone方法并在clone方法中进行调用。

protected Object clone() throws CloneNotSupportedException {

Son result = (Son) super.clone();

if (son != null) {

result.son = (Son) son.clone();

}

return result;

}

说几句废话

个人认为,在选择深克隆方法时,应根据对象的复杂程度,如引用类型属性是否有多层引用类型属性关系。如果对象只有一层或者两层引用类型的属性,选择思考中所提到的方法较为方便,反之则使用对象流。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值