我们来看一个不可变对象的攻守问题:

public  class   Period{private   final   Date   startTime;private   finale  Date   endTime;public   Period(Date  startTime , Date  endTime){if(startTime.compareTo(endTime) > 0){ throw   new  IllegalArgumentException(“startTime  after  endTime !”);  }this.startTime = startTime;this.endTime  = endTime;}pubilc   Date   start(){  return   this.startTime ; }public   Date  end(){ return  this.endTime  ; }}

这个类貌似是一个不可变类 ,因为startTime和endTime域都是final的,但是它并不是一个严格的不可变类,因为Date类并不是一个不可变类,所以Date实例指向内存中的引用地址不可变,但是引用的内容可以变,所以可以这样来攻击不可变类

Date  startTime   =  new Date();Date  endTime   = new  Date();Period  per =  new  Period(startTime ,  endTime );endTime.setYear(78);

这个时候我们对于构造器进行保护性拷贝

public   Period(Date   startTime , Date  endTime ){this.startTime  =  new Date (startTime.getTime());this.endTime   =  new  Date(endTime.getTime());if(this.startTime.compareTo(this.endTime)  >  0){ throw   new    IllegalArgumentException(“startTime  after   endTime !”);}}

也就是说把这个可变的Date引用指向了一个拷贝,这样endTime.setYear(78)永远也修改不了这个拷贝。

值得注意的是:保护性拷贝是在检查参数有效性之前进行的,而且针对的是拷贝对象。为什么呢?因为担心并发情况下检查有效性通过之后,另一个线程改变了可变对象使其有效性错误,但是依然能进行保护性拷贝的错误情况。

同时我们没有用Date的clone方法进行保护性拷贝。为什么呢?
因为Date是非final的,不能保证clone方法返回的就是Date对象,它有可能返回一个专门出于恶意目的而设计的不可信子类的实例。
例如:上面例子中如果别有用心之人新建了一个Mydate继承了Date
那么构造方法中就可以传入MyDate对象,那么调用的就是MyDate的clone方法,那么他就可以在clone方法上动手脚,把实例的引入记录起来,供攻击者访问。

还有一种攻击方法:

Date start = new Date();
Date end = new Date();
Period p = new Period(start, end);
p.end().setYear(78);

原因是它的访问方法提供了对其可变内部成员的访问能力。
解决方法是使它返回内部域的保护性拷贝。

public Date start() {return new Date(start.getTime());
}public Date end() {return new Date(end.getTime());
}

总结:参数的保护性拷贝策略不仅仅是针对不可变类,如果类具有从客户端得到或者返回到客户端的可变组件,类必须保护性地拷贝这些组件。如果受到拷贝成本的约束,就应该明确向客户端指明。

避免保护性拷贝的方法是将对象组件设置为不可变组件。或者把客户端和类放在同一个包中,不暴露出去。

Effective Java之必要时进行保护性拷贝(三十九)相关推荐

  1. Effective Java之注解优于命名模式(三十五)

    Java 1.5之前,一般使用命名模式表明有些程序元素需要通过某种工具或者框架进行特殊处理.例如,JUnit测试框架原本要求用户一定要用test作为测试方法名称的开头. 命名模式的缺点: 文字拼写错误 ...

  2. Effective Java之检查参数的有效性(三十八)

    检查参数的有效性实际上是满足了这一条普遍原则: 应该在发生错误之后尽快检测出错误. 例子: 有个数据库查询的例子,传入一个id,查出一个Student对象,然而返回null,如果没有及时检查这个实例是 ...

  3. Effective Java之坚持使用Overide注解(三十六)

    @Override 注解: 表示被注解的方法声明覆盖了超类型中的一个声明 1.我们应该在想要覆盖超类声明的每个方法声明中使用 Override 注解 ; 如果使用了Override注解的方法是重载而不 ...

  4. Effective Java之用EnumSet代替位域(三十二)

    什么是位域?为什么用到它? 先来看一个例子: public class Test {public static final byte STYLE_BOLD = 1<<0; // 1publ ...

  5. 三十九、Java集合中的HashSet和TreeSet

    @Author:Runsen @Date:2020/6/6 作者介绍:Runsen目前大三下学期,专业化学工程与工艺,大学沉迷日语,Python, Java和一系列数据分析软件.导致翘课严重,专业排名 ...

  6. 【零基础学Java】—List集合(三十九)

    [零基础学Java]-List集合(三十九) java.util.list接口 extends Collection接口 list接口的特点: 1.有序的集合,存储元素和取出元素的顺序是一致的(存储1 ...

  7. javaweb学习总结(三十九)——数据库连接池

    javaweb学习总结(三十九)--数据库连接池 一.应用程序直接获取数据库连接的缺点 用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长.假设网站一天10 ...

  8. 孤傲苍狼 只为成功找方法,不为失败找借口! javaweb学习总结(三十九)——数据库连接池 一、应用程序直接获取数据库连接的缺点   用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要

    孤傲苍狼 只为成功找方法,不为失败找借口! javaweb学习总结(三十九)--数据库连接池 一.应用程序直接获取数据库连接的缺点 用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对 ...

  9. NeHe OpenGL第三十九课:物理模拟

    NeHe OpenGL第三十九课:物理模拟 物理模拟简介: 还记得高中的物理吧,直线运动,自由落体运动,弹簧.在这一课里,我们将创造这一切.   物理模拟介绍 如果你很熟悉物理规律,并且想实现它,这篇 ...

最新文章

  1. 支持百亿请求的微博广告运维技术实践
  2. React事件系统整理
  3. 语言 蜗牛爬树问题_一年级语文《小蜗牛》课文解析及测试题,感觉最难的是口语交际题...
  4. 几个UI Prototype应用的使用感受
  5. SpaceVim的配置+ e121:undefined variable:g:spacevim global config path
  6. Android的Style的使用
  7. 【Linux】Linux crontab 命令详解
  8. 怎么看电脑系统是win几_一文看懂arm架构和x86架构有什么区别
  9. epoll的内核实现
  10. Git Flow工作流图
  11. linux确定刻录机目录,在Linux操作系统下使用DVD刻录机(转)
  12. YOLOv4改进版重磅问世!Yolov4原班人马重磅推出Scaled-YOLOv4!业界最佳
  13. jquery操作radio,checkbox
  14. elementui table某一列是否显示_汇编语言--键盘扫描及显示实验(含代码解释)
  15. 设置ListCtrl列表控件其中某一行的字体和背景颜色
  16. 和发光的人在一起,慢慢地你也会发光
  17. 红帽Linux7考题,RHCSA题库-RedHat-7.pdf
  18. 根据百度日历获取当年所有天数,以及判断今天是周几 以及是是节假日或者工作日,阴历阳历
  19. 华硕主板如何设置开机自启_教你华硕主板bios怎么设置硬盘启动
  20. 学的java,想问问现在想做电商的项目怎末样?

热门文章

  1. C++ STL 一般总结
  2. RedrawWindow, UpdateWindow,InvalidateRect 用法
  3. 告别DNS劫持,一文读懂DoH
  4. C语言程序设计 | 打印一个n行的菱形
  5. selenium的使用教程2
  6. 让互联网更快的协议,QUIC在腾讯的实践及性能优化
  7. Java类加载器(二)——自定义类加载器
  8. Django上传文件及分页
  9. 世界杯直播背后:腾讯云极速高清技术部署实录
  10. 腾讯里约——数字化中台的基石