InTheBloodHorse

Java中浅拷贝和深拷贝

字数统计: 872阅读时长: 4 min
2019/04/29 Share

什么是拷贝

Java中所有的类都默认继承了java.lang.Object类,而在java.lang.Object类中有一个方法clone()。

  1. 拷贝对象返回的是一个新对象,而不是一个引用。
  2. 拷贝过程中并不会进行构造方法,而是新对象已经包含了原来对象的信息。

实现Clone()方法

首先类实现Cloneable接口,另外就是重写clone()方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Teacher implements Cloneable {
private String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}

浅拷贝

浅拷贝是指拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象。假设初始有类Person和类Teacher,在类Person中引用了类Teacher。现在我们拷贝(浅拷贝)了Person得到了 newPerson,此时Person和newPerson的引用都指向了同一个对象,即Teacher。当我们对Teacher进行操作,例如更改Teacher名字为”1ni”,那么Person和newPerson的getTeacherName()的结果都是”1ni”。
例如上文的 super.clone()就是简单的浅拷贝。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
class Teacher implements Cloneable {
private String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}

class Person implements Cloneable {
private String name;
private Double score;
private Teacher teacher;


public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Double getScore() {
return score;
}

public Teacher getTeacher() {
return teacher;
}

public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}

public void setScore(Double score) {
this.score = score;
}

@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}

public class ShallowCopy {

public static void main(String[] args) throws CloneNotSupportedException {
Teacher teacher = new Teacher();
teacher.setName("yz");
Person s1 = new Person();
s1.setName("1ni");
s1.setScore(55.5);
s1.setTeacher(teacher);

System.out.println("s1: " + s1.getName() + " " + s1.getScore());

Person s2 = (Person) s1.clone();
System.out.println("s2: " + s2.getName() + " " + s2.getScore());
System.out.println("--------------------");
s2.getTeacher().setName("新老师Tony");
System.out.println("s1: " + s1.getName() + " " + s1.getTeacher().getName());
System.out.println("s2: " + s2.getName() + " " + s2.getTeacher().getName());
}
}

结果为

1
2
3
4
5
s1: 1ni 55.5
s2: 1ni 55.5
--------------------
s1: 1ni 新老师Tony
s2: 1ni 新老师Tony

深拷贝

深拷贝不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象

方法一

所以需要在Person中重写clone方法。对Person类中的Teacher对象进行一次拷贝

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Person implements Cloneable {
private String name;
private Double score;
private Teacher teacher;


public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Double getScore() {
return score;
}

public Teacher getTeacher() {
return teacher;
}

public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}

public void setScore(Double score) {
this.score = score;
}

@Override
protected Object clone() throws CloneNotSupportedException {
Person p = null;
p = (Person) super.clone();
p.setTeacher((Teacher) getTeacher().clone());
return p;
}
}

结果如下

1
2
3
4
5
s1: 1ni 55.5
s2: 1ni 55.5
--------------------
s1: 1ni yz
s2: 1ni 新老师Tony

方法二

可以考虑将对象序列化,再反序列化得到结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package inthebloodhorse.copy;

import java.io.*;

class Student implements Serializable {
private static final long serialVersionUID = 1L;
String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}


class ClassRoom implements Serializable {
private static final long serialVersionUID = 1L;
Student student;

public Student getStudent() {
return student;
}

public void setStudent(Student student) {
this.student = student;
}

public Object deepClone() throws IOException, ClassNotFoundException {
// 写进流里
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
// 从流里读出来
ByteArrayInputStream bi = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream oi = new ObjectInputStream(bi);
return oi.readObject();
}
}

public class Copy2 {

public static void main(String[] args) throws IOException, ClassNotFoundException {
ClassRoom classRoom1 = new ClassRoom();
Student student = new Student();
student.setName("123");
classRoom1.setStudent(student);
ClassRoom classRoom2 = (ClassRoom) classRoom1.deepClone();
classRoom1.getStudent().setName("1ni");
System.out.println(classRoom1.getStudent().getName());
System.out.println(classRoom2.getStudent().getName());
}
}

结果如下

1
2
教室一的学生:1ni
教室二的学生:123

原文作者:InTheBloodHorse

原文链接:http://pyking.cn/2019/04/29/Java中浅拷贝和深拷贝/

发表日期:April 29th 2019, 3:10:49 pm

更新日期:April 30th 2019, 12:38:51 pm

版权声明:Have a fun

CATALOG
  1. 1. 什么是拷贝
  2. 2. 实现Clone()方法
  3. 3. 浅拷贝
  4. 4. 深拷贝
    1. 4.1. 方法一
    2. 4.2. 方法二