快速业务通道

Java理论与实践: 变还是不变? - 编程入门网

作者 佚名技术 来源 NET编程 浏览 发布时间 2012-06-22
T 事件类都没有作为严格的不变类来实现,而是可以有小小的修改。同样 地,在使用一定形式的消息传递以在组件间通信的系统中,使消息对象成为不变 的或许是明智的。

编写不变类的准则

编写不变类很容易。如果以下几点都为真,那么类就是不变的:

它的所有字段都是 final

该类声明为 final

不允许 this 引用在构造期间转义

任何包含对可变对象(如数组、集合或类似 Date 的可变类)引用的字段:

是私有的

从不被返回,也不以其它方式公开给调用程序

是对它们所引用对象的唯一引用

构造后不会更改被引用对象的状态

最后一组要求似乎挺复杂的,但其基本上意味着如果要存储对数组或其它可 变对象的引用,就必须确保您的类对该可变对象拥有独占访问权(因为不然的话 ,其它类能够更改其状态),而且在构造后您不修改其状态。为允许不变对象存 储对数组的引用,这种复杂性是必要的,因为 Java 语言没有办法强制不对 final 数组的元素进行修改。注:如果从传递给构造函数的参数中初始化数组引 用或其它可变字段,您必须用防范措施将调用程序提供的参数或您无法确保具有 独占访问权的其它信息复制到数组。否则,调用程序会在调用构造函数之后,修 改数组的状态。清单 3 显示了编写一个存储调用程序提供的数组的不变对象的 构造函数的正确方法(和错误方法)。

清单 3. 对不变对象编码的正确和错误方法

class ImmutableArrayHolder {   private final int[] theArray;   // Right way to write a constructor -- copy the array   public ImmutableArrayHolder(int[] anArray) {    this.theArray = (int[]) anArray.clone();   }   // Wrong way to write a constructor -- copy the reference   // The caller could change the array after the call to the constructor   public ImmutableArrayHolder(int[] anArray) {    this.theArray = anArray;   }   // Right way to write an accessor -- don''t expose the array reference   public int getArrayLength() { return theArray.length }   public int getArray(int n) { return theArray[n]; }   // Right way to write an accessor -- use clone()   public int[] getArray()    { return (int[]) theArray.clone(); }   // Wrong way to write an accessor -- expose the array reference   // A caller could get the array reference and then change the contents   public int[] getArray()    { return theArray } }

通过一些其它工作,可以编写使用一些非 final 字段的不变类(例如, String 的标准实现使用 hashCode 值的惰性计算),这样可能比严格的 final 类执行得更好。如果类表示抽象类型(如数字类型或颜色)的值,那么您还会想 实现 hashCode() 和 equals() 方法,这样对象将作为 HashMap 或 HashSet 中 的一个键工作良好。要保持线程安全,不允许 this 引用从构造函数中转义是很 重要的。

偶尔更改的数据

有些数据项在程序生命期中一直保持常量,而有些会频繁更改。常量数据显 然符合不变性,而状态复杂且频繁更改的对象通常不适合用不变类来实现。那么 有时会更改,但更改又不太频繁的数据呢?有什么方法能让 有时更改的数据获 得不变性的便利和线程安全的长处呢?

util.concurrent 包中的 CopyOnWriteArrayList 类是如何既利用不变性的 能力,又仍允许偶尔修改的一个良好示例。它最适合于支持事件监听程序的类( 如用户界面组件)使用。虽然事件监听程序的列表可以更改,但通常它更改的频 繁性要比事件的生成少得多。

除了在修改列表时, CopyOnWriteArrayList 并不变更基本数组,而是创建 新数组且废弃旧数组之外,它的行为与

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站: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号