浅拷贝与深拷贝
在工作开发中,我们有时候需要将一份原始数据复制成一份新数据,再对新数据进行部分修改,这里就引出浅拷贝与深拷贝两个概念。
需要注意的是,浅拷贝和深拷贝是编程中的概念,它们并不局限于某一种语言,每种语言都有自己的浅拷贝/深拷贝方式。
什么是浅拷贝?
对于基本类型数据,浅拷贝复制了数据本身,而对于对象类型数据,浅拷贝只复制了对象的引用,而不是对象本身
因此,如果修改了浅拷贝后数据中的对象,那么原始数据中的对象也会受到影响
什么是深拷贝
对于基本类型数据,深拷贝复制了数据本身,而对于对象类型数据,深拷贝会递归复制对象的所有元素,包括对象类型
深拷贝后的数据是完全和原始数据独立的,因此对它进行任何操作都是安全的
Java中实现浅拷贝
使用Object.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
50public class Order implements Cloneable {
private String orderName;
private Long orderNo;
private Address address;
// 省略getter/setter
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Address {
private String country;
private String province;
private String city;
private String district;
private String detailAddress;
// 省略getter/setter
}
public class TestCopy {
public static void main(String[] args) throws CloneNotSupportedException {
Address address = new Address();
address.setCountry("中国");
address.setProvince("浙江省");
address.setCity("杭州市");
address.setDistrict("西湖区");
address.setDetailAddress("凤起路");
Order order = new Order();
order.setOrderName("双十一好物订单");
order.setOrderNo(202300156L);
order.setAddress(address);
System.out.println("order: " + order);
System.out.println("address: " + address);
System.out.println("detailAddress: " + address.getDetailAddress());
Order copyOrder = (Order) order.clone();
System.out.println("copyOrder: " + copyOrder);
System.out.println("copyAddress: " + copyOrder.getAddress());
copyOrder.getAddress().setDetailAddress("武林广场");
System.out.println("detailAddress: " + address.getDetailAddress());
}
}运行结果
1
2
3
4
5
6order: com.codecho.copy.Order@677327b6
address: com.codecho.copy.Address@14ae5a5
detailAddress: 凤起路
copyOrder: com.codecho.copy.Order@7f31245a
copyAddress: com.codecho.copy.Address@14ae5a5
detailAddress: 武林广场==可以看出,使用Object.clone()方法复制出了一个新的Order对象,但是Order对象内部的Address还是原来的Address对象,并且对新Order对象内部Address进行修改会影响到原Address对象,说明Object.clone()方法只是拷贝了对象的引用,并没有拷贝对象本身。==
使用apache或spring提供的BeanUtils工具类
代码示例
1
2
3
4
5<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.4</version>
</dependency>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
30public class TestCopy {
public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {
Address address = new Address();
address.setCountry("中国");
address.setProvince("浙江省");
address.setCity("杭州市");
address.setDistrict("西湖区");
address.setDetailAddress("凤起路");
Order order = new Order();
order.setOrderName("双十一好物订单");
order.setOrderNo(202300156L);
order.setAddress(address);
System.out.println("order: " + order);
System.out.println("address: " + address);
System.out.println("detailAddress: " + address.getDetailAddress());
Order copyOrder = new Order();
BeanUtils.copyProperties(copyOrder, order);
System.out.println("copyOrder: " + copyOrder);
System.out.println("copyAddress: " + copyOrder.getAddress());
copyOrder.getAddress().setDetailAddress("武林广场");
System.out.println("detailAddress: " + address.getDetailAddress());
}
}运行结果
1
2
3
4
5
6order: com.codecho.copy.Order@330bedb4
address: com.codecho.copy.Address@2503dbd3
detailAddress: 凤起路
copyOrder: com.codecho.copy.Order@685f4c2e
copyAddress: com.codecho.copy.Address@2503dbd3
detailAddress: 武林广场==和Object.clone()方法一样,BeanUtils.copyProperties()方法也是浅拷贝==
Java中实现深拷贝
序列化和反序列化
代码示例
==注意:Order和Address需要实现Serializable接口==
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
46public class Order implements Serializable {
...
}
public class Address implements Serializable {
...
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
Address address = new Address();
address.setCountry("中国");
address.setProvince("浙江省");
address.setCity("杭州市");
address.setDistrict("西湖区");
address.setDetailAddress("凤起路");
Order order = new Order();
order.setOrderName("双十一好物订单");
order.setOrderNo(202300156L);
order.setAddress(address);
System.out.println("order: " + order);
System.out.println("address: " + address);
System.out.println("detailAddress: " + address.getDetailAddress());
Order copyOrder = deepCopy(order);
System.out.println("copyOrder: " + copyOrder);
System.out.println("copyAddress: " + copyOrder.getAddress());
copyOrder.getAddress().setDetailAddress("武林广场");
System.out.println("detailAddress: " + address.getDetailAddress());
}
public static Order deepCopy(Order source) throws IOException, ClassNotFoundException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(outputStream);
out.writeObject(source);
ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
ObjectInputStream in = new ObjectInputStream(inputStream);
Order copy = (Order) in.readObject();
return copy;
}运行结果
1
2
3
4
5
6order: com.codecho.copy.Order@330bedb4
address: com.codecho.copy.Address@2503dbd3
detailAddress: 凤起路
copyOrder: com.codecho.copy.Order@7e6cbb7a
copyAddress: com.codecho.copy.Address@7c3df479
detailAddress: 凤起路