java浅拷贝深拷贝例子(Java深拷贝和浅拷贝的区别是什么)

浅拷贝:
  • 定义

比如A被B浅拷贝后,B的所有变量和A的所有变量相同,而且B所有对其他对象的引用任然指向原来的对象,也就是对像浅拷贝只会对主对象(就是A)本身进行拷贝,但不会对主对象里面的对象拷贝,A和B里面的对象引用相同,属于共享状态。

简单说就是,支付至所考虑的对象,而不复制它引用的对象。

  • 浅拷贝前提

首先对象浅拷贝需要实现接口Cloneable

Cloneable接口

java浅拷贝深拷贝例子(Java深拷贝和浅拷贝的区别是什么)(1)

空接口

Cloneable是标记型的接口(空接口),它们内部都没有方法和属性,实现 Cloneable来表示该对象能被克隆,能使用Object.clone()方法。如果没有实现 Cloneable的类对象调用clone()就CloneNotSupportedException异常。可以理解为Cloneable接口发挥的是标记功能,自定义类型需要用户自己标记出哪些类是可以clone的,这个标记就是去实现Cloneable接口,实现了Cloneable接口后就表明该类创建的对象可以被克隆。而要想使一个类具备拷贝实例的功能,除了要实现Cloneable接口,还必须重写Object类的clone()方法。

  • 代码详解

Group类实现:

super.clone()他会把原对象完整的拷贝过来包括其中的引用,属于欠拷贝

接下里是Group和Person类,用于浅拷贝

package com.consumer.test; public class Group implements Cloneable{ String groupName; Person person; public String getGroupName() { return groupName; } public void setGroupName(String groupName) { this.groupName = groupName; } public Person getPerson() { return person; } public void setPerson(Person person) { this.person = person; } @Override protected Object clone() throws CloneNotSupportedException { Object object = super.clone(); return object; } }

package com.consumer.test; public class Person implements Cloneable{ String name; String sex; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } }

  • 具体实现样例类ShallowCopy

public class ShallowCopy { public static void main(String[] args) throws CloneNotSupportedException { Person person = new Person(); person.setName("zhangSan"); person.setSex("17"); Group group = new Group(); group.setGroupName("1号组"); group.setPerson(person); Group groupCopy = (Group) group.clone(); System.out.println("浅拷贝后:"); System.out.println(groupCopy.getGroupName()); System.out.println(groupCopy.getPerson().getName()); System.out.println(groupCopy.getPerson().getSex()); System.out.println("修改Person信息后:"); person.setName("liSi"); person.setSex("28"); group.setGroupName("copy组"); System.out.println(groupCopy.getGroupName()); System.out.println(groupCopy.getPerson().getName()); System.out.println(groupCopy.getPerson().getSex()); } }

java浅拷贝深拷贝例子(Java深拷贝和浅拷贝的区别是什么)(2)

运行结果

从结果发现浅拷贝后复制得到的对象引用的person会随着原对象的改变而变化,但是直接属性String不会随着原对象的修改儿变化。

java浅拷贝深拷贝例子(Java深拷贝和浅拷贝的区别是什么)(3)

浅拷贝特点总结:

1.复制得到的对象本身是新对象

2.对象里面的基本数据会复制, 基本数据不存在引用;特殊的String类型,有深拷贝表现;

String 存在于堆内存、常量池;这种比较特殊, 本身没有实现 Cloneable, 传递是引用地址;

由本身的final性, 每次赋值都是一个新的引用地址,原对象的引用和副本的引用互不影响。

因此String就和基本数据类型一样,表现出了"深拷贝"特性.

3.对象里面的复杂数据类型会进行浅拷贝, 指向的同一个引用地址

深拷贝:

DeepGroup

package com.consumer.test; public class DeepGroup implements Cloneable{ String groupName; Person person; public String getGroupName() { return groupName; } public void setGroupName(String groupName) { this.groupName = groupName; } public Person getPerson() { return person; } public void setPerson(Person person) { this.person = person; } @Override protected Object clone() throws CloneNotSupportedException { DeepGroup deepGroup = (DeepGroup)super.clone(); // 本来是浅复制的,现在讲Person镀锌复制一份重新set进来,因为都是基本类型,都支持深拷贝 deepGroup.setPerson((Person) deepGroup.getPerson().clone()); return deepGroup; } }

Person

package com.consumer.test; public class Person implements Cloneable{ String name; String sex; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }

  • 具体深拷贝实例:

package com.consumer.test; public class DeepGroup implements Cloneable{ String groupName; Person person; public String getGroupName() { return groupName; } public void setGroupName(String groupName) { this.groupName = groupName; } public Person getPerson() { return person; } public void setPerson(Person person) { this.person = person; } @Override protected Object clone() throws CloneNotSupportedException { DeepGroup deepGroup = (DeepGroup)super.clone(); // 本来是浅复制的,现在讲Person镀锌复制一份重新set进来,因为都是基本类型,都支持深拷贝 deepGroup.setPerson((Person) deepGroup.getPerson().clone()); return deepGroup; } }

运行结果:

java浅拷贝深拷贝例子(Java深拷贝和浅拷贝的区别是什么)(4)

深拷贝结果

我们发现深拷贝后,复制得到的对象不会受到原来对象的修改而变化的影响了。

java浅拷贝深拷贝例子(Java深拷贝和浅拷贝的区别是什么)(5)

深拷贝总结:

所有属性都是一份拷贝, 跟原数据不会有任何耦合(不存在引用共享),我们目前是一层层浅拷贝,实现深拷贝,如果嵌套层次很多会很臃肿,当然我们可以序列化深拷贝: 不需要递归让所有对象实现cloneable接口, 方便简洁。

贴上深拷贝工具类:(此工具类的拷贝类必须都是实现了Serializable接口,支持序列化,否则会报错)

package com.consumer.test; import java.io.*; public class CloneUtils { @SuppressWarnings("unchecked") public static <T extends Serializable> T deepClone(T obj) { T cloneObj = null; try { //写入字节流 ByteArrayOutputStream out = new ByteArrayOutputStream(); ObjectOutputStream obs = new ObjectOutputStream(out); obs.writeObject(obj); obs.close(); //分配内存,写入原始对象,生成新对象 ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray()); ObjectInputStream ois = new ObjectInputStream(ios); //返回生成的新对象 cloneObj = (T) ois.readObject(); ois.close(); } catch (Exception e) { e.printStackTrace(); } return cloneObj; } }

序列化实现深拷贝实现:

package com.consumer.test; import com.alibaba.fastjson.JSONObject; public class DeepTest { public static void main(String[] args) throws Exception { Person person = new Person(); person.setName("zhangSan"); person.setSex("17"); DeepGroup deepGroup = new DeepGroup(); deepGroup.setGroupName("1号组"); deepGroup.setPerson(person); // 序列化——深拷贝 // 相当于重写字节流, 再创建新对象, 跟原对象没有任何引用共享, 无需嵌套重现 Cloneable.clone(), 只需要实现 Serializable (每个子类) System.out.println("----------------- 序列化-深拷贝测试1 ------------------"); // 工具类 DeepGroup deepGroupCopy = CloneUtils.deepClone(deepGroup); System.out.println("deepGroup == deepGroupCopy: " (deepGroup == deepGroupCopy)); System.out.println("deepGroup.person == deepGroupCopy.person: " (deepGroup.getPerson() == deepGroupCopy.getPerson())); System.out.println("deepGroup.person.name == deepGroupCopy.person.name: " (deepGroup.getPerson().getName() == deepGroupCopy.getPerson().getName())); System.out.println(JSONObject.toJSONString(deepGroup)); System.out.println(JSONObject.toJSONString(deepGroupCopy)); System.out.println("----------------- 序列化-深拷贝测试2 ------------------"); person.setName("liSi"); person.setSex("132"); System.out.println(JSONObject.toJSONString(deepGroup)); System.out.println(JSONObject.toJSONString(deepGroupCopy)); } }

运行结果:

java浅拷贝深拷贝例子(Java深拷贝和浅拷贝的区别是什么)(6)

我们发现序列化可以实现深拷贝,没有问题,到此ok。

java浅拷贝深拷贝例子(Java深拷贝和浅拷贝的区别是什么)(7)

  • 你究竟是害怕剑姬还是害怕满是破绽的自己。
如果看到这里,希望大家关注点赞一起交流哈。,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页