快速业务通道

Java理论与实践 - 它是谁的对象? - 编程入门网

作者 佚名技术 来源 NET编程 浏览 发布时间 2012-06-22
的引用时都使用这一技术,尤其 是在您编写一个通用的可能被不是您自己编写的代码调用(事实上这很常见)的 工具时更是如此。有别名的可变对象被意外修改的情况会以许多微妙且令人惊奇 的方式突然出现,并且调试起来相当困难。

而且情况还会变得更坏。假设您是Widget类的一个使用者,您并不知道存取 器具有值语义还是引用语义。谨慎的做法是,在调用存取器方法时也使用防御性 副本。所以,如果您想要将 w2 移动到 w1 的当前位置,您应该这样去做:

Point p = w1.getLocation(); w2.setLocation(new Point(p.x, p.y));

如果 Widget 像在版本 2 或 3 中一样实现其存取器,那么我们将为每个调 用创建两个临时对象 ――一个在 setLocation 调用的外面,一个在里面。

文档说明存取器语义

getLocation 和 setLocation 的版本 1 的真正问题不是它们易受混淆别名 副作用的不良影响(确实是这样),而是它们的语义没有清楚的说明。如果存取 器被清楚地说明为具有引用语义(而不是像通常那样被假设为值语义),那么调 用者将更可能认识到,在它们调用setLocation时,它们是将Point对象的所有权 转移给另一个实体,并且也不大可能仍然认为它们还拥有Point对象的所有权, 因而还能够再次使用它。

利用不可改变性解决以上问题

如果一开始就使得Point 成为不可变的,那么这些与 Point 有关的问题早就 迎刃而解了。不可变对象上没有副作用,并且缓存不可变对象的引用总是安全的 ,不会出现别名问题。如果 Point是不可变的,那么与setLocation 和 getLocation存取器的语义有关的所有问题都是非常确定的 。不可变属性的存取 器将总是具有值引用,因而调用的任何一方都不需要防御性复制,这使得它们效 率更高。

那么为什么不在一开始就使得Point 成为不可变的呢?这可能是出于性能上 的原因,因为早期的 JVM具有不太有效的垃圾收集器。那时,每当一个对象(甚 至是鼠标)在屏幕上移动就创建一个新的Point的对象创建开销可能有些让人生 畏,而创建防御性副本的开销则不在话下。

依后见之明,使Point成为可变的这个决定被证明对于程序清晰性和性能是昂 贵的代价。Point类的可变性使得每一个接受Point作为参数或者要返回一个 Point的方法背上了编写文档说明的沉重负担。也就是说,它得说明它是要改变 Point,还是在返回之后保留对Point的一个引用。因为很少有类真正包含这样的 文档,所以在调用一个没有用文档说明其调用语义或副作用行为的方法时,安全 的策略是在传递它到任何这样的方法之前创建一份防御副本。

有讽刺意味的是,使 Point成为可变的这个决定所带来的性能优势被由于 Point的可变性而需要进行的防御性复制给抵消了。由于缺乏清晰的文档说明( 或者缺少信任),在方法调用的两边都需要创建防御副本 ――调用者需要这样 做是因为它不知道被调用者是否会粗暴地改变 Point,而被调用者需要这样做是 因为它不知道是否保留了对 Point 的引用。

Java理论与实践 - 它是谁的对象?(4)

时间:2010-12-20

一个现实的例子

下面是悬空别名问题的另一个例子,该例子非常类似于我最近在一个服务器 应用中所看到的。该应用在内部使用了发布-订阅式消息传递方式,以将事件和 状态更新传达到服务器内的其他代理。这些代理可以订阅任何一个它们感兴趣的 消息流。一旦发布之后,传递到其他代理的消息就可能在将来某个时候在一个不 同的线程中被处理。

清单 4 显示了一个典型的消息传递事件(即发布拍卖系统中一个新的高投标 通知)和产生该事件的代码。不幸的是,消息传递事件实现和调用者实现的交互 合起来创建了一个悬空别名。通过简单地复制而不是克隆数组引用,消息和产生 消息的类都保存了前一投标数组的主副本的一个引用。如果消息发

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

分享到: 更多

Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号