String为什么设计成不可变
String为什么设计成不可变
- char数组的封装
- 具体设计
- final关键字修饰字符数组
- private关键字修饰
- 没有提供操作原数组的方法
- final修饰String类型杜绝子类覆盖
- 设计原因
- 帮助字符串常量池发挥作用
- 有助于哈希码的计算缓存
- 保证线程安全避免被修改
char数组的封装
C语言中就是用的char数组来表示的字符串,在Java的一切皆对象世界中,将char数组进行了封装,用String类型来表达字符串。
具体设计
点开String的源码就能发现char数组的身影,可以看到char数组被final关键字修饰,并且是私有成员变量。
1. final关键字修饰字符数组
单纯的字符数组被final关键字修饰,所以不可变。这个说法不准确。因为被final只代表它不可指向新的数组,又不能代表数组本身的数据不可被改变。
2. private关键字修饰
真正不可变的原因是因为它还被private修饰了。
3. 没有提供操作原数组的方法
并且String没有暴露和提供任何修改字符数组的方法。
一些字符串操作都是返回的新String对象,绝对不会影响原数据。获取其底层字符数组时,都是复制一个新数组进行返回。原数组也不会受到影响。
4. final修饰String类型杜绝子类覆盖
并且String类型还被final修饰了,代表其不可被继承。从而杜绝了子类覆盖父类行为的可能。
设计原因
1. 帮助字符串常量池发挥作用
首先,只有String不可变了,字符串常量池才能发挥作用。
用字面量创建字符串时,字符串常量池会返回已有对象的引用。如果字符串可变,那引用的值就可以随时修改,并能随时影响到其他的引用,从而数据会发生各种错误。这样常量池还谈何复用呢。
2. 有助于哈希码的计算缓存
然后,String不可变可以保证它的哈希码也不会变,因此计算一次哈希码后,就可以将其缓存。再用到时就无需计算了,性能更高。
也正是由于其哈希码不会变,所以可以放心去使用和哈希计算相关的对象,比如HashMap、HashSet。如果String的哈希码会改变,那就会影响到这些对象的哈希计算,从而导致预期之外的结果。
比如你之前明明存储了一个String对象,到后面你发现找不到原对象了。
3. 保证线程安全避免被修改
最后一个很重要的原因就是不可变对象都是线程安全的。因为你不用担心当前线程使用的对象会被其他线程修改。可以发现不可变对象有诸多优点,所以Java中有许多对象都设计成了不可变,比如BigDecimal。
参考资料:【每天一个技术点】String为什么不可变,有什么好处吗
还没有评论,来说两句吧...