`
TonyLian
  • 浏览: 396776 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

【第24条】需要时使用保护性拷贝

阅读更多

    Java受欢迎的一个重要原因是它是一门安全的语言。它对于缓冲区溢出、数组越界、非法指针以及其他内存破坏错误自动免疫。

 

    但是,这并不是说你可以高枕无忧,正如前面【第5条】中所述的,某些情况下你还是要自行回收过期引用的。现在我们再来说一下你不得不做的“自我防卫”性工作。

 

    【第5条】中的回收过期引用,即使你没有这么做,顶多是浪费一些内存资源。但是,如果本条所述的“自我防卫”工作你没有到位的话,那后果就可能是灾难性的了,而其错误所在往往不容易被发现。

 

     如果一个方法或构造函数允许可变对象进/出,那么就要考虑一下使用者是否有可能改变它。如果是的话,那你必须对该对象进行保护性拷贝,使进入方法内部的对象是外部时的拷贝而不它本身(因为外部的对象有可能还会被改变)。

 

public class Stuff {
    private String name;
    private Date birthday;

    public Stuff(String name, Date birthday) {
        this.name = name;
        this.birthday = birthday;
    }

    public Date getBrithday() {
        return this.birthday;
    }
}

 

这样的一个职员类,它包括姓名和生日。在没有进行保护性拷贝的保护之前,我们来看看攻击者(攻击者太极端了,很肯能是一个“高级”程序员)是如何开始他的破坏工作的:

 

Date day1 =  new Date(1970,1,1)
Stuff zhangSan = new Stuff("张三", day1);
// .......

// 几行其他代码之后,老先生有想起 day1 来了
day1.setYear(2009);

// 这下坏了,张三先生成了婴儿了,zhangSan.birthday = 2009-1-1

 

这样的原因就是Date型是一个可变类型(Java早期遗留下来的遗憾之一,详见【第13条】)。我们使用保护性拷贝来防之:

 

    public Stuff(String name, Date birthday) {
        this.name = name;
        this.birthday = new Date(birthday.getTime());   // 内部的birthday实际上在这里新创建的一个“日期值”等于实参的新实例
     // 因为,Date型是可变类型,所以“值”虽相等,也是新实例
    }

 

现在这位老先生无论怎么折腾 day1 也不会影响到 张三 大哥的生辰八字了。但是,人家老先生还有高招:

 

zhangSan.getBirthday().setYear(2010);
// 这回张三先生就更惨了,直接回娘胎了

 

如果getBrithday方法是我们必须提供的,那该怎么办呢?答案还是保护性拷贝:

 

    public Date getBrithday() {
        return (Date) this.birthday.clone();  // 我造个新的实例扔给你,你随便折腾吧,影响不到我
    }

 看到了吧,这就是保护性拷贝,使用构造函数也好,克隆也罢,总之是得到一个原对象的副本。

 

    最后要提一下包装类模式(包括适配器模式和装饰模式),根据包装类的本质特征,使用者只需直接访问被包装的对象,就可以破坏包装类的约束条件,但是,这样做的前提是确保不会伤害使用者自己。

 

 

 

【Effective Java 学习笔记】系列连载专题请见:
http://tonylian.iteye.com/categories/64208

 

5
0
分享到:
评论
1 楼 lord_is_layuping 2012-09-25  
copy on write就是一般不会复制,你改一个元素就修改一个,其它共享
http://en.wikipedia.org/wiki/Copy-on-write

如果不是immutable,可能经常要进行保护性拷贝
http://tonylian.iteye.com/blog/391256,保护性拷贝

保护性拷贝直接double了内存的占用
而且,如果在循环中进行保护性拷贝,那就不得了了

scala在后面折腾这些都是以性能为代价的。当然JVM本身也折腾,scala是进一步折腾 :-)

相关推荐

    网络安全管理制度(6).doc

    系统安全管理 第二十四条 禁止下载互联网上任何未经确认其安全性的软件,严禁使用盗版软件及游戏软件。 第二十五条 外来软盘或光盘须在未联网的单机上检查病毒,确认无毒后方可上网使用。私自使用造 成病毒侵害要...

    LINUX 24学时教程

    第二部分 学习Linux操作系统的基本命令 第4学时 阅读与浏览命令 46 4.1 使用man命令获取帮助 46 4.2 浏览及搜索文件系统 48 4.2.1 使用cd命令进入不同的目录 48 4.2.2 使用pwd命令查看自己所在的位置 48 4.2.3 使用...

    visio教程PDF

    第二部分 创建工程 第4章 使用样板创建新工程 4.1 从样板绘图开始 4.2 Block Diagram文件夹中的样板 4.2.1 Basic Diagram 4.2.2 Block Diagram with Perspective 4.2.3 Block Diagram 4.3 Flow...

    Visio 2000 技术大全

    第二部分 创建工程 第4章 使用样板创建新工程 4.1 从样板绘图开始 4.2 Block Diagram文件夹中的样板 4.2.1 Basic Diagram 4.2.2 Block Diagram with Perspective 4.2.3 Block Diagram 4.3 ...

    Reversing:逆向工程揭密

    第二类是从没有源代码的程序出发,生成对应的源程序、系统结构以及相关设计原理和算法思想的文档等,亦即本书重点讨论的二进制逆向工程。 本书共有13章和三个附录,涵盖了逆向工程的基础知识、应用、开发和拓展的...

    代码优化:有效使用内存.part3

    1.6.2第二步:将strlen函数体移出循环 1.6.3第三步:对齐数据 1.6.4第四步:删除strlen函数 1.6.5第五步:删除除法操作 1.6.6第六步:删除性能监测代码 1.6.7第七步:函数组合 1.6.8第八步:减少内存访问操作的次数 ...

    代码优化:有效使用内存.part2

    1.6.2第二步:将strlen函数体移出循环 1.6.3第三步:对齐数据 1.6.4第四步:删除strlen函数 1.6.5第五步:删除除法操作 1.6.6第六步:删除性能监测代码 1.6.7第七步:函数组合 1.6.8第八步:减少内存访问操作的次数 ...

    代码优化:有效使用内存.part1

    1.6.2第二步:将strlen函数体移出循环 1.6.3第三步:对齐数据 1.6.4第四步:删除strlen函数 1.6.5第五步:删除除法操作 1.6.6第六步:删除性能监测代码 1.6.7第七步:函数组合 1.6.8第八步:减少内存访问操作的次数 ...

    会计理论考试题

    第二套 选择题 1.PC机中 Intel8088、80286、80386、80486,PemiumPⅡ、PⅢ是指_D_的不同型号。 A、显示器 B、内存储器 C、外存储器 D、微处理器 2.用高级语言来编写的程序 ___D___ 。 A、称为编译软件 B、经编译后,...

    windows用户称拦截api

    总结:windows进程所需要的动态库文件都是以写入时拷贝的方式映射到进程地址空间中的。这样,我们只能拦截指定的进程。修改目标进程地址空间中的指定api的入口和出口地址之间的任意数据,使之跳转到我们的拦截代码中...

    大数据中心信息数据管理制度.doc

    六、对于政府决策、公共安全、国防建设、环境保护、防灾减灾、公益性科学研究 等需要使用数据的,应当无偿提供;确需收费的,应按照规定程序和非营利原则制定合 理的收费标准,向社会公布并接受监督.对于因经营性...

    大数据中心信息数据管理制度(1).doc

    六、对于政府决策、公共安全、国防建设、环境保护、防灾减灾、公益性科学研究 等需要使用数据的,应当无偿提供;确需收费的,应按照规定程序和非营利原则制定合理 的收费标准,向社会公布并接受监督.对于因经营性活动...

    vc++ 应用源码包_1

    任务管理器应该大家都很熟悉,论坛里也有好多的任务管理器的源码,解决CListCtr刷新时滚动条跳到开始处。 VC++实现网络连接查看器源码 非常好的一个实例,把网络连接的UDP/TCP都插入到CList控件中显示出来。 VC++...

    大数据中心信息数据管理制度(3).doc

    六、对于政府决策、公共安全、国防建设、环境保护、防灾减灾、公益性科学 研究等需要使用数据的,应当无偿提供;确需收费的,应按照规定程序和非营利原则制 定合理的收费标准,向社会公布并接受监督。对于因经营性...

    vc++ 应用源码包_2

    任务管理器应该大家都很熟悉,论坛里也有好多的任务管理器的源码,解决CListCtr刷新时滚动条跳到开始处。 VC++实现网络连接查看器源码 非常好的一个实例,把网络连接的UDP/TCP都插入到CList控件中显示出来。 VC++...

    vc++ 应用源码包_6

    任务管理器应该大家都很熟悉,论坛里也有好多的任务管理器的源码,解决CListCtr刷新时滚动条跳到开始处。 VC++实现网络连接查看器源码 非常好的一个实例,把网络连接的UDP/TCP都插入到CList控件中显示出来。 VC++...

    vc++ 应用源码包_5

    任务管理器应该大家都很熟悉,论坛里也有好多的任务管理器的源码,解决CListCtr刷新时滚动条跳到开始处。 VC++实现网络连接查看器源码 非常好的一个实例,把网络连接的UDP/TCP都插入到CList控件中显示出来。 VC++...

    vc++ 应用源码包_3

    任务管理器应该大家都很熟悉,论坛里也有好多的任务管理器的源码,解决CListCtr刷新时滚动条跳到开始处。 VC++实现网络连接查看器源码 非常好的一个实例,把网络连接的UDP/TCP都插入到CList控件中显示出来。 VC++...

Global site tag (gtag.js) - Google Analytics