警惕数组的浅拷贝

简介:

一、分析 

在日常工作中,我们会遇见很多数组的拷贝和复制的问题,但是在你使用系统提供的API进行编码的时候,无形中会留下浅拷贝的隐患。

二、场景 

有这样一个例子,第一个箱子里面与赤橙黄绿青蓝紫7色气球,现在希望第二个箱子也放入7个气球,其中最后一个气球改为蓝色,也就是赤橙黄绿青蓝蓝七个气球。

复制代码
 1 import org.apache.commons.lang3.builder.ToStringBuilder;
 2 
 3 public class Client{ 
 4     public static void main(String[] args){ 
 5         //气球的数量 
 6         int ballonNum = 7; 
 7         //第一个箱子 
 8         Ballon[] box1 = new Ballon[ballonNum]; 
 9         //初始化第一个箱子 
10         for(int i = 0; i < ballonNum; i++){ 
11             box1[i] = new Ballon(Color.values()[i],i); 
12         } 
13 
14         //第二个箱子的小球是拷贝的第一个箱子里的 
15         Ballon[] box2 = Arrays.copyOf(box1,box1.length); 
16         //修改最后一个气球的颜色 
17         box2[6].setColor(Color.Blue); 
18         //打印出第一个箱子中的气球颜色 
19         for(Ballon b:box1){ 
20             System.out.println(b); 
21         } 
22     } 
23 } 
24 
25 //气球的颜色 
26 enum Color{ 
27     Red,Orange,Yellow,Green,Indigo,Blue,Violet; 
28 } 
29 
30 //气球 
31 class Ballon{ 
32     //编号 
33     private int id; 
34     //颜色 
35     private Color color; 
36 
37     public int getId() {
38         return id;
39     }
40 
41     public void setId(int id) {
42         this.id = id;
43     }
44 
45     public Color getColor() {
46         return color;
47     }
48 
49     public void setColor(Color color) {
50         this.color = color;
51     }
52 
53     public Ballon(Color _color,int _id){ 
54         color = _color; 
55         id = _id; 
56     } 
57 
58     /*id、color的getter/setter方法省略*/ 
59     //apache-common包下的ToStringBuilder重写toString方法 
60     public String toString(){ 
61         return new ToStringBuilder(this).append("编号",id).append("颜色",color).toString(); 
62     } 
63 }
复制代码

第二个箱子的最后一个气球毫无疑问是被修改了蓝色,不过是通过拷贝第一个箱子的气球实现的,那么会对第一个箱子的气球颜色有影响吗?输出结果:

Balloon@b2fd8f[编号=0,颜色=Red]

Balloon@a20892[编号=1,颜色=Orange]

Balloon@158b649[编号=2,颜色=Yellow]

Balloon@1037c71[编号=3,颜色=Green]

Balloon@1546e25[编号=4,颜色=Indigo]

Balloon@8a0d5d[编号=5,颜色=Blue]

Balloon@a470b8[编号=6,颜色=Blue]

最后一个气球竟然被修改了。这是为何?

这是典型的浅拷贝(Shallow Clone)问题,通过copyOf()方法产生的数组是一个浅拷贝引用地址。需要说明的是数组的clone()方法也是与此相同,同样是浅拷贝,而且集合的clone()方法也是浅拷贝。这就需要大家多留心了。

问题找到了,解决办法也很简单,遍历box1的每个元素,重新生成一个气球(Ballon)对象,并放置到box2数组中。

很多地方使用集合(如List)进行业务处理时,比如发觉需要拷贝集合中的元素,可集合没有提供任何拷贝方法,所以干脆使用 List.toArray方法转换成数组,然后通过Arrays.copyOf拷贝,然后转换成集合,简单便捷!但是,非常遗憾,这里我们有撞到浅拷贝的 枪口上了!!!!

三、建议 

虽然很多时候浅拷贝可以解决业务问题,但更多的时候会留下隐患,需要我们提防又提防。

 


本文转自SummerChill博客园博客,原文链接:http://www.cnblogs.com/DreamDrive/p/5422216.html,如需转载请自行联系原作者

相关文章
|
5月前
|
JSON 前端开发 JavaScript
JavaScript拷贝大作战:浅拷贝vs深拷贝
JavaScript拷贝大作战:浅拷贝vs深拷贝
82 0
|
5月前
|
编译器 C++ Python
【C/C++ 泡沫精选面试题02】深拷贝和浅拷贝之间的区别?
【C/C++ 泡沫精选面试题02】深拷贝和浅拷贝之间的区别?
88 1
|
8天前
|
存储 JSON 前端开发
栈在前端中的应用,顺便再了解下深拷贝和浅拷贝!
该文章探讨了栈在前端开发中的应用,并深入讲解了JavaScript中深拷贝与浅拷贝的区别及其实现方法。
栈在前端中的应用,顺便再了解下深拷贝和浅拷贝!
|
3月前
|
前端开发 JavaScript
前端深拷贝、浅拷贝,一起手撕深拷贝
【7月更文挑战第2天】JavaScript中的深拷贝和浅拷贝关乎对象复制的独立性。浅拷贝(如`Object.assign()`、扩展运算符)创建新对象,但共享引用类型属性的内存地址,导致修改新对象会影响原始对象。深拷贝(如递归复制)创建完全独立的对象副本,不受原始对象变动影响。`JSON.parse(JSON.stringify(obj))`是简单的深拷贝方法,但无法处理函数、undefined、Symbol及循环引用。手动实现深拷贝需递归遍历并处理循环引用问题,以确保复制的完整性。理解这两者差异对编写健壮的代码至关重要。
22 0
|
4月前
|
JavaScript JSON 前端开发
深/浅拷贝,有哪些实现方式
深/浅拷贝,有哪些实现方式
|
5月前
|
前端开发 JavaScript
对象解构与迭代器的猫腻?
这篇文章介绍了变量的解构赋值技巧在前端开发中的常用性,包括对象解构和数组解构。文章中给出了一些代码示例,解释了可迭代对象的概念以及如何使用迭代协议来实现数组解构。此外,文章还介绍了生成器的概念并提供了代码示例。作者建议对这些概念不熟悉的读者可以查阅ES6的文档来更好地理解。
对象解构与迭代器的猫腻?
|
5月前
|
JavaScript 前端开发
JS中浅拷贝和深拷贝的区别,浅拷贝的危害
JS中浅拷贝和深拷贝的区别,浅拷贝的危害
30 0
|
5月前
|
存储 JSON JavaScript
10分钟深入探讨带你彻底理解浅拷贝与深拷贝
在JavaScript中,对象的拷贝是一项常见的操作。浅拷贝和深拷贝是两种常用的拷贝方式。浅拷贝只复制对象的引用,而深拷贝创建了一个全新的对象,包含与原始对象相同的值和结构。深拷贝和浅拷贝各有适用的场景和注意事项。本文将详细介绍如何实现一个完整而优雅的深拷贝函数,处理循环引用和特殊类型,优化性能,并探讨深拷贝和浅拷贝的应用场景、注意事项和相关属性。
|
5月前
|
存储 Java Apache
【面试问题】深拷贝和浅拷贝的区别?
【1月更文挑战第27天】【面试问题】深拷贝和浅拷贝的区别?
|
11月前
|
JavaScript
一文弄懂浅拷贝和深拷贝
一文弄懂浅拷贝和深拷贝
44 0