可变对象和不可变对象
在面向对象的系统中,存在可变对象(mutable)和不可变对象(immutable)两种对象,本文基于Java语言进行对比分析。
顾名思义,可变对象是创建之后状态可以改变的对象,不可变对象则是创建之后状态不可改变的对象。
一个对象包含的内部使用的属性改变了,但从外部看对象的状态并没有改变,例如一个使用Memoization来缓存复杂计算结果的对象仍然被看作是不可变对象。
不可变对象有几个优点:
- 线程安全
- 易于理解
- 比可变对象有更高的安全性
在面向对象编程中,String以及其他的具体对象都被看作是不可变对象,以提高可读性和运行效率。
尽管String类声明中没有提供让它成为不可变对象的语法,但是String类没有提供方法去改变一个String包含的数据,而是返回一个新的对象,这就使得它是不可变的。
Java字符串不可变的原因:
- 字符串常量池的需要:字符串常量池是 Java 堆内存中一个特殊的存储区域,当创建一个 String 对象时,假如此字符串值已经存在于常量池中,则不会创建一个新的对象,而是引用已经存在的对象。
- 允许 String 对象缓存 HashCode:Java 中 String 对象的哈希码被频繁地使用,比如在 HashMap 等容器中。字符串不变性保证了 hash 码的唯一性,因此可以放心地进行缓存。这也是一种性能优化手段,意味着不必每次都去计算新的哈希码。
- String 被许多的 Java 类(库)用来当做参数,例如网络连接地址 URL、文件路径 path、还有反射机制所需要的 String 参数等,假若 String 不是固定不变的,将会引起各种安全隐患。
Java中关键字final用于声明原始数据类型和对象引用为不可变对象,但是它不能使对象本身变为不可变对象。
- 原始数据类型变量(int, long, short等)定义之后还可以再重新赋值,可以使用final阻止这样的赋值。
- 仅仅使用final关键字还不能让引用类型(reference types)成为不可变对象,final只能阻止重新赋值。
原始类型包装类(Integer、Long、Short、Double、Float、Character、Byte、Boolean)也都是不可变的。
说明
本文首发于CSDN,为博主本人创作,修改后搬运至阿里云开发者社区发表。