0%

浅拷贝与深拷贝

前言:学习总结浅拷贝与深拷贝

概念

拷贝

java中的对象拷贝(Object Copy)指的是将一个对象的所有属性(成员变量)拷贝到另一个有着相同类类型的对象中去

浅拷贝与深拷贝。

在Java语言里,当我们需要拷贝一个对象时,有两种类型的拷贝:浅拷贝(Shallow Copy)与深拷贝(Deep Copy)。

基本数据类型,直接进行值传递,浅拷贝与深拷贝一样

String略特殊,因为字符串实际是不可修改的,存放在常量池中,但代码层的表现与对象是一样的

浅拷贝只是拷贝了源对象的地址,所以源对象的值发生变化时,拷贝对象的值也会发生变化。(同一个引用,同一个对象)

深拷贝则是拷贝了源对象的所有值,所以即使源对象的值发生变化时,拷贝对象的值也不会改变。(不同的引用,不同的对象(同一个类))

实现方式
  1. 构造函数
  2. 实现Cloneable接口并重写Object的clone()方法或者
  3. 对象序列化实现深拷贝

Bean类

Address类
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
/**
* @author shency
* @description: TODO
*/
public class Address {
private String province;
private String city;

public Address() {
}

public Address(String province, String city) {
this.province = province;
this.city = city;
}

public String getCity() {
return city;
}

public void setCity(String city) {
this.city = city;
}

public String getProvince() {
return province;
}

public void setProvince(String province) {
this.province = province;
}
}
User类
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
/**
* @author shency
* @description: TODO
*/
public class User {
private String username;
private Address address;

public User() {
}

public User(String username,Address address){
this.username = username;
this.address = address;
}
public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public Address getAddress() {
return address;
}

public void setAddress(Address address) {
this.address = address;
}
}

通过构造方法拷贝

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* @author shency
* @description: TODO
*/
class Solution {
public static void main(String[] args) {
User user = new User("张三",new Address("广东","深圳"));

// 浅拷贝
User copyUser1 = new User(user.getUsername(),user.getAddress());

// 深拷贝
User copyUser2 = new User(user.getUsername(),new Address(user.getAddress().getProvince(),user.getAddress().getCity()));

// 浅拷贝 两个引用指向同一个对象
System.out.println(user.getAddress() == copyUser1.getAddress());

// 深拷贝 两个引用指向不用对象
System.out.println(user.getAddress() == copyUser2.getAddress());
}
}

结果

1
2
true
false

通过clone()浅拷贝

User类实现Cloneable类并重写clone方法

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* @author shency
* @description: TODO
*/
public class User implements Cloneable{
private String username;
private Address address;

// 省略构造、get、set方法

@Override
public Object clone() {
Object obj = null;
try {
obj = super.clone();
} catch (Exception e) {
e.printStackTrace();
}
return obj;
}
}
1
2
3
4
5
6
7
8
9
10
11
/**
* @author shency
* @description: TODO
*/
class Solution {
public static void main(String[] args) {
User user = new User("张三",new Address("广东","深圳"));
User copyUser = (User)user.clone();
System.out.println(user.getAddress() == copyUser.getAddress());
}
}

结果

true

通过clone()深拷贝

与通过重写clone方法实现浅拷贝的基本思路一样,只需要为对象图的每一层的每一个对象都实现Cloneable接口并重写clone方法,最后在最顶层的类的重写的clone方法中调用所有的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
/**
* @author shency
* @description: TODO
*/
public class User implements Cloneable{
private String username;
private Address address;

// 省略构造、set、get方法

@Override
public Object clone() {
Object obj = null;
try {
obj = super.clone();
// 调用属性的clone
User user = (User)obj;
user.setAddress((Address)user.getAddress().clone());
} catch (Exception e) {
e.printStackTrace();
}
return obj;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* @author shency
* @description: TODO
*/
public class Address implements Cloneable{
private String province;
private String city;

// 省略构造、set、get方法

@Override
public Object clone() {
Object obj = null;
try {
obj = super.clone();
} catch (Exception e) {
e.printStackTrace();
}
return obj;
}
}

结果

false

序列化实现深拷贝

代码

实现Serializable接口

1
2
3
4
5
6
7
public class Address implements Serializable {

}

public class User implements Serializable {

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* @author shency
* @description: TODO
*/
class Solution {
public static void main(String[] args) {
User user = new User("张三", new Address("广东", "深圳"));
//通过序列化方法实现深拷贝
User copyUser = null;
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(user);
oos.flush();
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
copyUser = (User) ois.readObject();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(user.getAddress() == copyUser.getAddress());
}
}

工具类依赖

1
2
3
4
5
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
12
/**
* @author shency
* @description: TODO
*/
class Solution {
public static void main(String[] args) {
User user = new User("张三", new Address("广东", "深圳"));
//通过序列化方法实现深拷贝
User copyUser = SerializationUtils.clone(user);
System.out.println(user.getAddress() == copyUser.getAddress());
}
}

结果

false

总结

image-20200101224101034

-------------本文结束感谢您的阅读-------------