java 深拷贝_Java的深拷贝与浅拷贝

鄙人写文章喜欢简洁点,希望用尽可能短的语句描述一个知识点

1、概述

拷贝的一个经典的使用场景:当前对象要传给其他多个方法使用,如果该对象在某一个方法中被修改,那么这个修改会影响到其他方法。 如果要避免这种影响,就需要给每一个方法都传入一个当前对象的拷贝。

深与浅拷贝的区别就在于对复杂对象的处理:对于基本类型,浅拷贝、深拷贝都是拷贝的值;对于引用类型浅拷贝的是对象的引用。而深拷贝则是直接新建一个对象实例。

注意浅拷贝中的复杂引用以及简单引用:对于简单引用,拷贝后的对象指向新的地址不会影响到原对象。复杂引用,拷贝后的对象将内部的对象指向新的地址,会影响到原对象对应的内部对象。这里一定理解下,抓住“地址”指向去理解就好了。

2、代码实现

(1)浅拷贝实现方式:类实现Cloneable接口,并且重写clone()方法。详细见下面的代码

(2)深拷贝:主要是针对类内部的复杂引用变量。两种方式:1)复杂引用也实现Cloneable,并重写clone()方法,然后在父对象重写的clone方法中将该复杂引用指向克隆后的引用  2)直接将需要克隆的对象进行序列化,然后反序列化就可以得到一个深拷贝的对象。

当然这些工作都有现成的轮子了,借助于Apache Commons工具类可以直接实现:

浅克隆:BeanUtils.cloneBean(Object obj);

深克隆:SerializationUtils.clone(T object);

当然可以直接使用

2.1浅拷贝

父子类

1 @Data2 @Builder3 class Father implementsCloneable {4 Long age;5 StringBuilder name;6 Son son;7

8 @Override9 publicObject clone() {10 //浅拷贝

11 try{12 return super.clone();13 } catch(CloneNotSupportedException e) {14 e.printStackTrace();15 return null;16 }17 }18 }19

20 @Data21 @Builder22 classSon {23 Long age;24 String name;25 intgrade;26 }

初始赋值

1 public static Son son = Son.builder().age(new Long(30L)).name("大儿子").grade(100).build();2 public static Father father = Father.builder().age(new Long(50L)).name("爸爸").son(son).build();

浅拷贝示例:

private static voidshallowClone() {

System.out.println("父亲年龄:" +father.getAge());

System.out.println("父亲姓名:" +father.getName());

System.out.println("儿子年龄:" +father.getSon().getAge());

System.out.println("儿子姓名:" +father.getSon().getName());

System.out.println("儿子分数:" +father.getSon().getGrade());//开始克隆

Father fatherInLaw=(Father) father.clone();

fatherInLaw.getSon().setAge(10L);

fatherInLaw.getSon().setGrade(0);

fatherInLaw.getSon().setName("继子");

fatherInLaw.setAge(new Long(80L));

fatherInLaw.setName("继父");//修改后结果

System.out.println("==========浅拷贝后===========");

System.out.println("父亲年龄:" +father.getAge());

System.out.println("父亲姓名:" +father.getName());

System.out.println("儿子年龄:" +father.getSon().getAge());

System.out.println("儿子姓名:" +father.getSon().getName());

System.out.println("儿子分数:" +father.getSon().getGrade());

}

结果输出

父亲年龄:50父亲姓名:爸爸

儿子年龄:30儿子姓名:大儿子

儿子分数:100

==========浅拷贝后===========父亲年龄:50父亲姓名:爸爸

儿子年龄:10儿子姓名:继子

儿子分数:0

2.2.深拷贝

(1)子引用重写clone方法,并且在父类中改变子引用的指向

父子类

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

@Data

@Builderclass Father implementsCloneable {

Long age;

StringBuilder name;

Son son;

@OverridepublicObject clone() {

Father father= null;//浅拷贝

try{

father= (Father) super.clone();

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

}catch(CloneNotSupportedException e) {

e.printStackTrace();return null;

}returnfather;

}

}

@Data

@Builderclass Son implementsCloneable {

Long age;

String name;intgrade;

@OverridepublicObject clone() {//拷贝

try{return super.clone();

}catch(CloneNotSupportedException e) {

e.printStackTrace();return null;

}

}

}

View Code

赋初值

1 public static Son son = Son.builder().age(new Long(30L)).name("大儿子").grade(100).build();2 public static Father father = Father.builder().age(new Long(50)).name(new StringBuilder("爸爸")).son(son).build();

深拷贝示例:

//深拷贝

private static voiddeepClone() {

System.out.println("父亲年龄:" +father.getAge());

System.out.println("父亲姓名:" +father.getName());

System.out.println("儿子年龄:" +father.getSon().getAge());

System.out.println("儿子姓名:" +father.getSon().getName());

System.out.println("儿子分数:" +father.getSon().getGrade());//开始克隆

Father fatherInLaw=(Father) father.clone();

fatherInLaw.getSon().setAge(10L);

fatherInLaw.getSon().setGrade(0);

fatherInLaw.getSon().setName("继子");

fatherInLaw.setAge(new Long(80L));

fatherInLaw.setName(new StringBuilder("继父"));//修改前

System.out.println("==========浅拷贝后===========");

System.out.println("父亲年龄:" +father.getAge());

System.out.println("父亲姓名:" +father.getName());

System.out.println("儿子年龄:" +father.getSon().getAge());

System.out.println("儿子姓名:" +father.getSon().getName());

System.out.println("儿子分数:" +father.getSon().getGrade());

}

结果

父亲年龄:50父亲姓名:爸爸

儿子年龄:30儿子姓名:大儿子

儿子分数:100

==========浅拷贝后===========父亲年龄:50父亲姓名:爸爸

儿子年龄:30儿子姓名:大儿子

儿子分数:100

(2)序列化方式

父子类

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

@Data

@Builderclass Father implementsSerializable {

Long age;

StringBuilder name;

Son son;public Object deepClone() throwsIOException, ClassNotFoundException {//序列化

ByteArrayOutputStream bos = newByteArrayOutputStream();

ObjectOutputStream oos= newObjectOutputStream(bos);

oos.writeObject(this);//反序列化

ByteArrayInputStream bis = newByteArrayInputStream(bos.toByteArray());

ObjectInputStream ois= newObjectInputStream(bis);returnois.readObject();

}

}

@Data

@Builderclass Son implementsSerializable {

Long age;

String name;intgrade;

}

View Code

实现方法

//深拷贝

private static void deepCloneV2() throwsIOException, ClassNotFoundException {

System.out.println("父亲年龄:" +father.getAge());

System.out.println("父亲姓名:" +father.getName());

System.out.println("儿子年龄:" +father.getSon().getAge());

System.out.println("儿子姓名:" +father.getSon().getName());

System.out.println("儿子分数:" +father.getSon().getGrade());//开始克隆

Father fatherInLaw=(Father) father.deepClone();

fatherInLaw.getSon().setAge(10L);

fatherInLaw.getSon().setGrade(0);

fatherInLaw.getSon().setName("继子");

fatherInLaw.setAge(new Long(80L));

fatherInLaw.setName(new StringBuilder("继父"));//修改前

System.out.println("==========浅拷贝后===========");

System.out.println("父亲年龄:" +father.getAge());

System.out.println("父亲姓名:" +father.getName());

System.out.println("儿子年龄:" +father.getSon().getAge());

System.out.println("儿子姓名:" +father.getSon().getName());

System.out.println("儿子分数:" +father.getSon().getGrade());

}

结果:

父亲年龄:50父亲姓名:爸爸

儿子年龄:30儿子姓名:大儿子

儿子分数:100

==========浅拷贝后===========父亲年龄:50父亲姓名:爸爸

儿子年龄:30儿子姓名:大儿子

儿子分数:100

3、使用Apach  Commons

3.1实现深拷贝,需要实现序列化接口,SerializationUtils.clone(T object);

父子类

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

@Data

@Builderclass Father implementsSerializable{

Long age;

StringBuilder name;

Son son;

}

@Data

@Builderclass Son implementsSerializable{

Long age;

String name;intgrade;

}

View Code

实现方法

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

//深拷贝

private static void deepCloneCommons() throwsIOException, ClassNotFoundException {

System.out.println("父亲年龄:" +father.getAge());

System.out.println("父亲姓名:" +father.getName());

System.out.println("儿子年龄:" +father.getSon().getAge());

System.out.println("儿子姓名:" +father.getSon().getName());

System.out.println("儿子分数:" +father.getSon().getGrade());//开始克隆

Father fatherInLaw=(Father) SerializationUtils.clone(father);

fatherInLaw.getSon().setAge(10L);

fatherInLaw.getSon().setGrade(0);

fatherInLaw.getSon().setName("继子");

fatherInLaw.setAge(new Long(80L));

fatherInLaw.setName(new StringBuilder("继父"));//修改前

System.out.println("==========浅拷贝后===========");

System.out.println("父亲年龄:" +father.getAge());

System.out.println("父亲姓名:" +father.getName());

System.out.println("儿子年龄:" +father.getSon().getAge());

System.out.println("儿子姓名:" +father.getSon().getName());

System.out.println("儿子分数:" +father.getSon().getGrade());

}

View Code

结果

父亲年龄:50父亲姓名:爸爸

儿子年龄:30儿子姓名:大儿子

儿子分数:100

==========深拷贝后===========父亲年龄:50父亲姓名:爸爸

儿子年龄:30儿子姓名:大儿子

儿子分数:100

3.2使用工具类实现浅拷贝

BeanUtils.copyProperties(Object dest, Object orig)直接调用即可实现浅拷贝,BeanUtils.cloneBean(Object obj)最终也是调用的copyProperties方法。

今日学习笔记到此结束。

书于:2019/08/01/ 22:40分

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值