为什么需要不可变类?
为什么需要不可变类?
不可变类一旦创建,其状态就不能被修改,这带来了多个方面的好处
包括:
- 线程安全性
- 简化代码
- 提高性能
- …
不可变类不代表类内变量不可变,而是状态(字段值)不可变
线程安全性
多线程环境中的安全性:由于不可变对象一旦创建就不能改变状态,它们天生是线程安全的。
多个线程可以安全地共享和访问同一个不可变对象,而不需要同步机制来避免并发修改的问题。
简化代码
减少复杂性:不可变对象的状态不会改变,因此在处理它们时,不需要考虑对象状态的变化。这简化了代码,减少了错误的可能性。
安全性:不可变对象可以安全地传递给方法、存储在集合中或返回给调用者,而不需要担心它们会在其他地方被修改。
提高性能
缓存:不可变对象可以被缓存和重用。一个典型的例子是字符串池(String Pool),其中相同的字符串字面量被缓存,以减少内存使用和提高性能。
哈希码缓存:由于不可变对象的状态不变,它们的哈希码也不会变化。因此,可以在创建对象时计算并缓存哈希码,以提高集合(如哈希表和哈希集)的性能。
易于维护和调试
更容易理解和维护:由于不可变对象的状态一旦创建就不变,理解和维护这些对象的代码变得更加容易。开发者可以确信,一旦对象被构建,它的状态不会在后续代码中被改变。
避免副作用
无副作用:不可变对象在方法调用中不会产生副作用。方法调用返回结果,不会改变对象本身的状态,因此不需要担心对象状态在方法调用后被意外改变。
不可变类示例
一个典型的不可变类的设计示例是 Java 中的 String
类。
String 类内部使用 private final char[] 存储字符串,通过私有+不暴露setter方法来维持不可变
创建不可变类的规则
要创建一个不可变类,需要遵循以下规则:
- 声明类为
final
:防止子类继承并改变类的行为。 - 所有字段都声明为
private
和final
:防止字段在对象创建后被修改。 - 没有提供修改字段的方法(setter 方法):确保对象的状态在创建后不能被改变。
- 确保对象的状态在构造时完全初始化:通过构造方法初始化所有字段。
- 如果类包含可变对象的字段,确保这些字段在对象创建后不能被修改:
- 在构造方法中,使用防御性复制来初始化这些字段。
- 不要直接暴露这些可变对象的引用。
示例:包含可变对象的不可变类
1 | import java.util.Date; |
在这个示例中,通过使用防御性复制来初始化 Date
对象,并在 getter 方法中返回 Date
对象的防御性复制,确保了不可变性。
结论
不可变类提供了线程安全性、简化代码、提高性能和避免副作用等诸多优势。
通过遵循创建不可变类的规则,开发者可以设计出更加健壮和易于维护的代码。
不可变类在多线程编程、集合类的使用以及确保数据一致性等方面具有重要意义。