龙空技术网

Java clone() 浅克隆与深度克隆

水心青云 28

前言:

此时我们对“java克隆”都比较关注,你们都需要了解一些“java克隆”的相关内容。那么小编同时在网摘上搜集了一些对于“java克隆””的相关知识,希望同学们能喜欢,兄弟们快快来学习一下吧!

Java clone() 浅克隆与深度克隆

现在Clone已经不是一个新鲜词语了,伴随着“多莉”的产生这个词语确实很“火”过一阵子,在java中也有这么一个概念,它可以让我们很方便的“制造”出一个对象的副本来,下面来具体看看java中的Clone机制是如何工作的?

1. Clone&Copy

假设现在有一个Employee对象,Employee tobby =new Employee(“CMTobby”,5000),通

常我们会有这样的赋值Employee cindyelf=tobby,这个时候只是简单了copy了一下reference,cindyelf和tobby都指向内存中同一个object,这样cindyelf或者tobby的一个操作都可能影响到对方。打个比方,如果我们通过cindyelf.raiseSalary()方法改变了salary域的值,那么tobby通过getSalary()方法得到的就是修改之后的salary域的值,显然这不是我们愿意看到的。我们希望得到tobby的一个精确拷贝,同时两者互不影响,这时候我们就可以使用Clone来满足我们的需求。Employee cindy=tobby.clone(),这时会生成一个新的Employee对象,并且和tobby具有相同的属性值和方法。

2. Shallow Clone&Deep Clone

Clone是如何完成的呢?Object在对某个对象实施Clone时对其是一无所知的,它仅仅是简单地执行域对域的copy,这就是Shallow Clone。这样,问题就来了咯,以Employee为例,它里面有一个域hireDay不是基本型别的变量,而是一个reference变量,经过Clone之后就会产生一个新的Date型别的reference,它和原始对象中对应的域指向同一个Date对象,这样克隆类就和原始类共享了一部分信息,而这样显然是不利的,过程下图所示:

这个时候我们就需要进行deep Clone了,对那些非基本型别的域进行特殊的处理,例如本例中的hireDay。我们可以重新定义Clone方法,对hireDay做特殊处理,如下代码所示:

[java] view plaincopy

1. class Employee implements Cloneable

2.

3. {

4. public Object clone() throws CloneNotSupportedException

5. {

6. Employee cloned = (Employee) super.clone();

7. cloned.hireDay = (Date) hireDay.clone()

8. return cloned;

9. }

10. }

3. Clone()方法的保护机制

在Object中Clone()是被申明为protected的,这样做是有一定的道理的,以Employee

类为例,通过申明为protected,就可以保证只有Employee类里面才能“克隆”Employee对象,原理可以参考我前面关于public、protected、private的学习笔记。

4. Clone()方法的使用

Clone()方法的使用比较简单,注意如下几点即可:

a. 什么时候使用shallow Clone,什么时候使用deep Clone,这个主要看具体对象的域是什么性质的,基本型别还是reference variable

b. 调用Clone()方法的对象所属的类(Class)必须implements Clonable接口,否则在调用Clone方法的时候会抛出CloneNotSupportedException。

1.java里的clone分为:

A:浅复制(浅克隆): 浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。

b:深复制(深克隆):深复制把要复制的对象所引用的对象都复制了一遍。

Java中对象的克隆,为了获取对象的一份拷贝,我们可以利用Object类的clone()方法。必须要遵循下面三点

1.在派生类中覆盖基类的clone()方法,并声明为public【Object类中的clone()方法为protected的】。

2.在派生类的clone()方法中,调用super.clone()。

3.在派生类中实现Cloneable接口。

Object类里的clone方法是浅复制(浅克隆)

浅复制(浅克隆)的例子如下:

Java代码

1. package com.test;

2.

3. //浅复制(浅克隆): 浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。

4. //深复制(深克隆):深复制把要复制的对象所引用的对象都复制了一遍。

5. //

6. //Java中对象的克隆,为了获取对象的一份拷贝,我们可以利用Object类的clone()方法。必须要遵循下面三点

7. //1.在派生类中覆盖基类的clone()方法,并声明为public【Object类中的clone()方法为protected的】。

8. //2.在派生类的clone()方法中,调用super.clone()。

9. //3.在派生类中实现Cloneable接口。

10.

11. //[color=red]Object类里的clone方法是浅复制(浅克隆)[/color]public class CloneTest {

12.

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

14. //teacher对象将被clone出来的Student对象共享.

15. Teacher teacher = new Teacher();

16. teacher.setAge(40);

17. teacher.setName("Teacher zhang");

18.

19. Student student1 = new Student();

20. student1.setAge(20);

21. student1.setName("zhangsan");

22. student1.setTeacher(teacher);

23.

24. //复制出来一个对象student2

25. Student student2 = (Student)student1.clone();

26. System.out.println(student2.getAge());

27. System.out.println(student2.getName());

28.

29.

30. System.out.println("~~~~~~~~~~~~~~~~~~~~~~");

31. System.out.println(student1.getTeacher().getAge());

32. System.out.println(student1.getTeacher().getName());

33.

34.

35. //修改student2的引用对象

36. student2.getTeacher().setAge(50);

37. student2.getTeacher().setName("Teacher Li");

38.

39. System.out.println("~~~~~~~~~~~~~~~~~~~~~~");

40. System.out.println(student1.getTeacher().getAge());

41. System.out.println(student1.getTeacher().getName());

42. }

43. }

44.

45. class Teacher {

46. public int age;

47. public String name;

48.

49. public int getAge() {

50. return age;

51. }

52. public void setAge(int age) {

53. this.age = age;

54. }

55. public String getName() {

56. return name;

57. }

58. public void setName(String name) {

59. this.name = name;

60. }

61.

62.

63. }

64.

65. class Student implements Cloneable{

66.

67. public int age ;

68. public String name;

69. public Teacher teacher;

70. public int getAge() {

71. return age;

72. }

73. public void setAge(int age) {

74. this.age = age;

75. }

76. public String getName() {

77. return name;

78. }

79. public void setName(String name) {

80. this.name = name;

81. }

82. public Teacher getTeacher() {

83. return teacher;

84. }

85. public void setTeacher(Teacher teacher) {

86. this.teacher = teacher;

87. }

88. @Override

89. public Object clone() throws CloneNotSupportedException {

90. return super.clone();

91. }

92.

93.

94. }

95. 输出结果为:

96. 20

97. zhangsan

98. ~~~~~~~~~~~~~~~~~~~~~~

99. 40

100. Teacher zhang

101. ~~~~~~~~~~~~~~~~~~~~~~

102. 50

103. Teacher Li

2.深复制(深Clone)例子:

Java代码

1. package com.test1;

2.

3. //深clone

4. public class DeepCloneTest {

5.

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

7. //teacher对象将不被clone出来的Student对象共享.

8. Teacher teacher = new Teacher();

9. teacher.setAge(40);

10. teacher.setName("Teacher zhang");

11.

12. Student student1 = new Student();

13. student1.setAge(20);

14. student1.setName("zhangsan");

15. student1.setTeacher(teacher);

16.

17. //复制出来一个对象student2

18. Student student2 = (Student)student1.clone();

19. System.out.println(student2.getAge());

20. System.out.println(student2.getName());

21.

22.

23. System.out.println("~~~~~~~~~~~~~~~~~~~~~~");

24. System.out.println(student1.getTeacher().getAge());

25. System.out.println(student1.getTeacher().getName());

26.

27.

28. //修改student2的引用对象

29. student2.getTeacher().setAge(50);

30. student2.getTeacher().setName("Teacher Li");

31.

32. System.out.println("~~~~~~~~~~~~~~~~~~~~~~");

33. System.out.println(student1.getTeacher().getAge());

34. System.out.println(student1.getTeacher().getName());

35. }

36. }

37.

38. class Teacher implements Cloneable{

39. public int age;

40. public String name;

41.

42. public int getAge() {

43. return age;

44. }

45. public void setAge(int age) {

46. this.age = age;

47. }

48. public String getName() {

49. return name;

50. }

51. public void setName(String name) {

52. this.name = name;

53. }

54. @Override

55. public Object clone() throws CloneNotSupportedException {

56. return super.clone();

57. }

58.

59. }

60.

61. class Student implements Cloneable{

62.

63. public int age ;

64. public String name;

65. public Teacher teacher;

66. public int getAge() {

67. return age;

68. }

69. public void setAge(int age) {

70. this.age = age;

71. }

72. public String getName() {

73. return name;

74. }

75. public void setName(String name) {

76. this.name = name;

77. }

78. public Teacher getTeacher() {

79. return teacher;

80. }

81. public void setTeacher(Teacher teacher) {

82. this.teacher = teacher;

83. }

84. @Override

85. public Object clone() throws CloneNotSupportedException {

86. Student student = (Student)super.clone();

87. //将引用的对象teacher也clone下

88. student.setTeacher((Teacher)(student.getTeacher().clone()));

89. return student;

90. }

91.

92.

93. }

94. 输出结果为:

95. 20

96. zhangsan

97. ~~~~~~~~~~~~~~~~~~~~~~

98. 40

99. Teacher zhang

100. ~~~~~~~~~~~~~~~~~~~~~~

101. 40

102. Teacher zhang

3.利用序列化来做深复制,把对象写到流里的过程是序列化(Serilization)过程,而把对象从流中读出来的过程则叫做反序列化(Deserialization)过程。应当指出的是,写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。,利用这个特性,可以做深拷贝

Java代码

1. package com.test3;

2.

3. import java.io.ByteArrayInputStream;

4. import java.io.ByteArrayOutputStream;

5. import java.io.ObjectInputStream;

6. import java.io.ObjectOutputStream;

7. import java.io.Serializable;

8. //利用序列化来做深复制

9. //深clone

10. public class DeepCloneTest {

11.

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

13. //teacher对象将不被clone出来的Student对象共享.

14. Teacher teacher = new Teacher();

15. teacher.setAge(40);

16. teacher.setName("Teacher zhang");

17.

18. Student student1 = new Student();

19. student1.setAge(20);

20. student1.setName("zhangsan");

21. student1.setTeacher(teacher);

22.

23. //复制出来一个对象student2

24. Student student2 = (Student)student1.deepCopy();

25. System.out.println(student2.getAge());

26. System.out.println(student2.getName());

27.

28.

29. System.out.println("~~~~~~~~~~~~~~~~~~~~~~");

30. System.out.println(student1.getTeacher().getAge());

31. System.out.println(student1.getTeacher().getName());

32.

33.

34. //修改student2的引用对象

35. student2.getTeacher().setAge(50);

36. student2.getTeacher().setName("Teacher Li");

37.

38. System.out.println("~~~~~~~~~~~~~~~~~~~~~~");

39. System.out.println(student1.getTeacher().getAge());

40. System.out.println(student1.getTeacher().getName());

41. }

42. }

43.

44. class Teacher implements Serializable{

45.

46. private static final long serialVersionUID = -8834559347461591191L;

47.

48. public int age;

49. public String name;

50.

51. public int getAge() {

52. return age;

53. }

54. public void setAge(int age) {

55. this.age = age;

56. }

57. public String getName() {

58. return name;

59. }

60. public void setName(String name) {

61. this.name = name;

62. }

63.

64. }

65.

66. class Student implements Serializable{

67.

68. //serialVersionUID 如果你的对象序列化后存到硬盘上面后,可是后来你却更改了类的field(增加或减少或改名),当你反序列化时,就会出现Exception的,这样就会造成不兼容性的问题。

69. //但当serialVersionUID相同时,它就会将不一样的field以type的缺省值赋值(如int型的是0,String型的是null等),这个可以避开不兼容性的问题。所以最好给serialVersionUID赋值

70. private static final long serialVersionUID = 7991552226614088458L;

71.

72. public int age ;

73. public String name;

74. public Teacher teacher;

75. public int getAge() {

76. return age;

77. }

78. public void setAge(int age) {

79. this.age = age;

80. }

81. public String getName() {

82. return name;

83. }

84. public void setName(String name) {

85. this.name = name;

86. }

87. public Teacher getTeacher() {

88. return teacher;

89. }

90. public void setTeacher(Teacher teacher) {

91. this.teacher = teacher;

92. }

93.

94. public Object deepCopy() throws Exception{

95. //将该对象序列化成流,因为写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。所以利用这个特性可以实现对象的深拷贝

96. ByteArrayOutputStream bos = new ByteArrayOutputStream();

97.

98. ObjectOutputStream oos = new ObjectOutputStream(bos);

99.

100. oos.writeObject(this);

101.

102. //将流序列化成对象

103. ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());

104.

105. ObjectInputStream ois = new ObjectInputStream(bis);

106.

107. return ois.readObject();

108. }

109.

110.

111. }

112. 输出结果为:

113. 20

114. zhangsan

115. ~~~~~~~~~~~~~~~~~~~~~~

116. 40

117. Teacher zhang

118. ~~~~~~~~~~~~~~~~~~~~~~

119. 40

120. Teacher zhang

��]~

标签: #java克隆