前言
说到不可变对象,想必大部分人都不会生疏。Java 程序员在日常开发过程中 100% 会用到的 String 对象就属于不可变对象吗,明天咱们就来聊聊不可变对象这个话题。
什么是不可变对象
《Effective Java》中是这样定义不可变对象的:
不可变对象(Immutable Object):对象一旦被创立后,对象所有的状态及属性在其生命周期内不会产生任何变动。
简略的说,就是一个对象在创立后,不能对该对象进行任何更改。比方上面这段代码:
public class ImmutableObject {
private int value;
public ImmutableObject(int value) {this.value = value;}
public int getValue() {return this.value;}
}
因为 ImmutableObject 不提供任何 setter 办法,并且成员变量 value 是根本数据类型,getter 办法返回的是 value 的拷贝,所以一旦 ImmutableObject 实例被创立后,该实例的状态无奈再进行更改,因而该类具备不可变性。
String 类
咱们常见的 String 类,为什么说字符串是不可变的?我的代码中常常扭转 String 的值啊!如下所示:
String string = "ABC";
string = string.concat("DE");
这样,下面的字符串不就扭转成 ”ABCDE” 了么?然而实际上,咱们失去的曾经是一个新的字符串。
程序会在堆中从新创立一个 ”ABCDE” 字符串,和 ”ABC” 并不是同一个对象。
所以,一旦一个 string 对象在内存 (堆) 中被创立进去,他就无奈被批改。而且,String 类的所有办法都没有扭转字符串自身的值,都是返回了一个新的对象。
string 类如何设计成不可变
- String 类被 final 关键字润饰,所以它不会有子类,这就意味着没有子类能够重写它的办法,扭转它的行为。
- String 类的数据存储在 char[] 数组中,而这个数组也被 final 关键字润饰了,这就示意 String 对象是没法被批改的,只有初始化一次,值就确定了。
不可变的益处
安全性
String 是 Java 中最根底也是最长应用的类,常常用于存储一些敏感信息,例如用户名、明码、网络连接等。因而,String 类的安全性对于整个应用程序至关重要。
节俭空间(字符串常量池)
通过应用常量池,内容雷同的字符串能够应用同一个对象,从而节俭内存空间。如果 String 是可变的,试想一下,当字符串常量池中的某个字符串对象被很多中央援用时,此时批改了这个对象,则所有援用的中央都会扭转,这可能会导致预期之外的状况。
性能
String 被广泛应用于 HashMap、HashSet 等哈希类中,当对这些哈希类进行操作时,例如 HashMap 的 get/put,hashCode 会被频繁调用。
线程平安
String 对象是不可批改的,如果线程尝试批改 String 对象,会创立新的 String,所以不存在并发批改同一个对象的问题。
因为不可变性,String 的 hashCode 只须要计算 1 次后就能够缓存起来,因而在哈希类中应用 String 对象能够晋升性能。
总结
因为字符串是不可变的,因而它们的援用能够被视为一般变量,能够在办法之间和线程之间传递它们,而不用放心它所指向的理论字符串对象是否会扭转。
本文由 mdnice 多平台公布