建议62:警惕数组的浅拷贝

一、分析 

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

二、场景 

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

 import org.apache.commons.lang3.builder.ToStringBuilder;

 public class Client{
public static void main(String[] args){
//气球的数量
int ballonNum = 7;
//第一个箱子
Ballon[] box1 = new Ballon[ballonNum];
//初始化第一个箱子
for(int i = 0; i < ballonNum; i++){
box1[i] = new Ballon(Color.values()[i],i);
} //第二个箱子的小球是拷贝的第一个箱子里的
Ballon[] box2 = Arrays.copyOf(box1,box1.length);
//修改最后一个气球的颜色
box2[6].setColor(Color.Blue);
//打印出第一个箱子中的气球颜色
for(Ballon b:box1){
System.out.println(b);
}
}
} //气球的颜色
enum Color{
Red,Orange,Yellow,Green,Indigo,Blue,Violet;
} //气球
class Ballon{
//编号
private int id;
//颜色
private Color color; public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public Color getColor() {
return color;
} public void setColor(Color color) {
this.color = color;
} public Ballon(Color _color,int _id){
color = _color;
id = _id;
} /*id、color的getter/setter方法省略*/
//apache-common包下的ToStringBuilder重写toString方法
public String toString(){
return new ToStringBuilder(this).append("编号",id).append("颜色",color).toString();
}
}

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

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拷贝,然后转换成集合,简单便捷!但是,非常遗憾,这里我们有撞到浅拷贝的 枪口上了!!!!

三、建议 

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

最新文章

  1. sqlplus 中spool命令的简单用法
  2. html+css-----补
  3. unigui判断浏览器内核、操作系统以及是否移动终端函数
  4. ACCESS-delphi向中插入一条记录报错,但ACCESS不会
  5. vagrant 入门2
  6. node.js简单搭建服务,访问本地站点文件
  7. Axure 入门学习
  8. ThinkPHP 数据库操作(四) : 聚合查询、时间查询、高级查询
  9. java多线程之AtomicLong与LongAdder
  10. PHP反射学习总结
  11. Python网络编程Socket之协程
  12. MVC 获取控制器名称和Action名称(转载)
  13. inheritPrototypeChain.js
  14. solidity ecrecover
  15. 小学四则运算APP 最后阶段
  16. CSS3实现鼠标移动到图片上图片变大(缓慢变大,有过渡效果,放大的过程是有动画过渡的,这个过渡的时间可以自定义)
  17. 女性睾酮水平高(High Testosterone Levels in Women)
  18. mybatis 参数为String,用_parameter 取值
  19. mysql 数据库优化第一篇(基础)
  20. 2017-2018-1 20155320第十周课下作业-IPC

热门文章

  1. POJ 2185 Milking Grid(KMP)
  2. #c word转换PDF
  3. 栈的简单应用 HDU 1022 http://acm.hdu.edu.cn/showproblem.php?pid=1022
  4. HDU1856More is better(并查集)
  5. 绑定线程到特定CPU处理器
  6. Unity3D之Mecanim动画系统学习笔记(四):Animation State
  7. do{...}while(0)的作用
  8. MPAndroiddChart的使用
  9. 逐行读取txt
  10. Chronometer控件实现的Android计时器