数据拷贝是计算机系统中常用的操作,在编程语言中也存在拷贝,这里简单描述一下程序中的拷贝操作

使用实例代码解析深拷贝和浅拷贝

商品实体类:

  1. package com.copy;
  2. /**
  3. * 商品信息
  4. *
  5. * @author lemon
  6. */
  7. public class Commodity implements Cloneable{
  8. private String commodityName;
  9. public String getCommodityName() {
  10. return commodityName;
  11. }
  12. public void setCommodityName(String commodityName) {
  13. this.commodityName = commodityName;
  14. }
  15. @Override
  16. protected Object clone() throws CloneNotSupportedException {
  17. return super.clone();
  18. }
  19. @Override
  20. public String toString() {
  21. return "Commodity{" +
  22. "commodityName='" + commodityName + '\'' +
  23. '}';
  24. }
  25. }

订单实体类:
  1. package com.copy;
  2. /**
  3. * 订单信息
  4. *
  5. * @author lemon
  6. */
  7. public class Order implements Cloneable{
  8. private Integer orderId;
  9. private Commodity commodity;
  10. public Integer getOrderId() {
  11. return orderId;
  12. }
  13. public void setOrderId(Integer orderId) {
  14. this.orderId = orderId;
  15. }
  16. public Commodity getCommodity() {
  17. return commodity;
  18. }
  19. public void setCommodity(Commodity commodity) {
  20. this.commodity = commodity;
  21. }
  22. @Override
  23. protected Object clone() throws CloneNotSupportedException {
  24. Order order=(Order)super.clone();
  25. order.setCommodity((Commodity) commodity.clone());
  26. return order;
  27. }
  28. @Override
  29. public String toString() {
  30. return "Order{" +
  31. "orderId=" + orderId +
  32. ", commodity=" + commodity +
  33. '}';
  34. }
  35. }

学生实体类:

  1. package com.copy;
  2. /**
  3. * 定义一个引用数据类型对象
  4. *
  5. * @author lemon
  6. */
  7. public class Student implements Cloneable{
  8. /**
  9. * 学生姓名
  10. */
  11. private String name;
  12. /**
  13. * 学生年龄
  14. */
  15. private int age;
  16. public Student() {
  17. }
  18. public Student(String name, int age) {
  19. this.name = name;
  20. this.age = age;
  21. }
  22. public int getAge() {
  23. return age;
  24. }
  25. public void setAge(int age) {
  26. this.age = age;
  27. }
  28. public String getName() {
  29. return name;
  30. }
  31. public void setName(String name) {
  32. this.name = name;
  33. }
  34. @Override
  35. public String toString() {
  36. return "Student{" +
  37. "name='" + name + '\'' +
  38. ", age=" + age +
  39. '}';
  40. }
  41. @Override
  42. public Object clone() throws CloneNotSupportedException {
  43. return super.clone();
  44. }
  45. }

测试代码:

  1. package com.copy;
  2. /**
  3. * 浅拷贝示例
  4. *
  5. * @author lemon
  6. */
  7. public class DataCopy {
  8. /**
  9. * 基本数据类型-拷贝
  10. */
  11. public void baseDataTypeCopy() {
  12. int num1 = 10;
  13. int num2 = num1;
  14. System.out.println("num1 数据值:" + num1);
  15. System.out.println("num2 数据值:" + num2);
  16. System.out.println("修改num1的数据值,查看会不会影响到num2的数据值");
  17. num1++;
  18. System.out.println("num1最新数据值:" + num1);
  19. System.out.println("num2最新数据值:" + num2);
  20. }
  21. /**
  22. * 引用数据类型-引用拷贝
  23. */
  24. public void referenceDataTypeCopy() throws CloneNotSupportedException{
  25. //Student A
  26. Student stuA = new Student("小A", 18);
  27. //Student B
  28. Student stuB =stuA;
  29. System.out.println("通过copy的方式,初始化学生对象");
  30. System.out.println(stuA);
  31. System.out.println(stuB);
  32. stuA.setName("小C");
  33. stuA.setAge(28);
  34. System.out.println("修改StuA的信息,查看StuA和StuB的信息变化");
  35. System.out.println(stuA);
  36. System.out.println(stuB);
  37. }
  38. /**
  39. * 引用数据类型-浅拷贝
  40. */
  41. public void shallowCopy() throws CloneNotSupportedException{
  42. //Student A
  43. Student stuA = new Student("小A", 18);
  44. //Student B
  45. Student stuB = (Student) stuA.clone();
  46. System.out.println("通过copy的方式,初始化学生对象");
  47. System.out.println(stuA);
  48. System.out.println(stuB);
  49. stuA.setName("小C");
  50. stuA.setAge(28);
  51. System.out.println("修改StuA的信息,查看StuA和StuB的信息变化");
  52. System.out.println(stuA);
  53. System.out.println(stuB);
  54. }
  55. /**
  56. * 引用数据类型-深拷贝
  57. */
  58. public void deepCopy() throws CloneNotSupportedException{
  59. Commodity apple=new Commodity();
  60. apple.setCommodityName("Apple");
  61. Order appleOrder=new Order();
  62. appleOrder.setCommodity(apple);
  63. appleOrder.setOrderId(1);
  64. Order appleOrders=(Order)appleOrder.clone();
  65. System.out.println(appleOrder);
  66. System.out.println(appleOrders);
  67. apple.setCommodityName("HongFuShi Apple");
  68. System.out.println(appleOrder);
  69. System.out.println(appleOrders);
  70. }
  71. }
  72. class DataCopyMain{
  73. public static void main(String[]args) throws CloneNotSupportedException{
  74. DataCopy copyDemo=new DataCopy();
  75. /**
  76. * 基本数据类型拷贝
  77. *
  78. * 运行结果:
  79. * num1 数据值:10
  80. * num2 数据值:10
  81. * 修改num1的数据值,查看会不会影响到num2的数据值
  82. * num1最新数据值:11
  83. * num2最新数据值:10
  84. */
  85. copyDemo.baseDataTypeCopy();
  86. /**
  87. * 引用数据类型-引用拷贝
  88. *
  89. * 运行结果:
  90. * 通过copy的方式,初始化学生对象
  91. * Student{name='小A', age=18}
  92. * Student{name='小A', age=18}
  93. * 修改StuA的信息,查看StuA和StuB的信息变化
  94. * Student{name='小C', age=28}
  95. * Student{name='小C', age=28}
  96. */
  97. copyDemo.referenceDataTypeCopy();
  98. /**
  99. * 引用数据类型-浅拷贝
  100. *
  101. * 运行结果:
  102. * 通过copy的方式,初始化学生对象
  103. * Student{name='小A', age=18}
  104. * Student{name='小A', age=18}
  105. * 修改StuA的信息,查看StuA和StuB的信息变化
  106. * Student{name='小C', age=28}
  107. * Student{name='小A', age=18}
  108. */
  109. copyDemo.shallowCopy();
  110. /**
  111. * 引用数据类型-深拷贝
  112. *
  113. * 运行结果:
  114. * Order{orderId=1, commodity=Commodity{commodityName='Apple'}}
  115. * Order{orderId=1, commodity=Commodity{commodityName='Apple'}}
  116. * Order{orderId=1, commodity=Commodity{commodityName='HongFuShi Apple'}}
  117. * Order{orderId=1, commodity=Commodity{commodityName='Apple'}}
  118. */
  119. copyDemo.deepCopy();
  120. }
  121. }

1.baseDataTypeCopy()基本数据类型
只是简单的值引用,所以当`num1`发生改变的时候,`num2`不受影响。

未命名文件.jpg

引申的问题:

java中的基本数据类型在栈中是存放在什么位置的?
**涉及到的 JVM区域: 方法栈、堆内存

在方法中声明局部变量,每当程序调用方法时,系统都会为该方法建立一个方法栈,所在方法中声明的变量就放在方法栈中,当方法结束系统会释放方法栈,其对应在该方法中声明的变量随着栈的销毁而结束,这就局部变量只能在方法中有效的原因!

方法局部变量:

基本数据类型:当声明是基本类型的变量的时是放在**方法栈**中

引用数据类型:声明的变量(栈地址非数据值)是放在方法栈中,该变量所指向的对象是放在**堆内存**中

类的成员变量:

基本数据类型:当声明的是基本类型的变量,会放在**堆内存**中的

引用数据类型:其声明的变量(栈地址非数据值)放在**方法栈**,该变量所指向的对象是放在**堆内存**中

2.referenceDataTypeCopy()引用数据类型拷贝
使用 `=` 进行引用传递,两个对象的数据使用的是一个堆内存,也就是虚拟机栈是一个地址,所以修改任意一个对象的信息,另一个都会受到影响。

未命名文件 (1).jpg

3.shallowCopy()引用数据类型的浅拷贝
同``referenceDataTypeCopy()`方法一样,对象中包含的引用数据类型不会在堆内存中划分空间,所以,浅拷贝的对象如果包含引用数据类型,这个引用数据和被引用对象的引用数据类型使用的一个栈地址。

未命名文件.png

4.deepCopy()引用数据类型的深拷贝
对象中包含的引用数据类型如果实现了`Cloneable`接口,并且重写了`Clone()`方法。那么,在克隆这个对象的时候,对象中的引用数据类型会在堆内存中划分空间。所以,深拷贝的对象包含的引用类型数据,发生改变不会修改被拷贝对象的数据信息。

未命名文件 (2).jpg

待补充的部分

文中提到的关于`Jvm`相关的部分,因为对部分知识点不是太了解,可能会存在出入,堆栈方法区等部分需要查询一些资料,这块有瑕疵的地方,请记得留言,以后会跟进修改一下。

-End-

_
公众号:Java编码日志
qrcode_for_gh_f247e3bfaf7a_258.jpg