前言:
此时我们对“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克隆