String类为什么是不可变的?StringBuilder和StringBuffer的区别,字符串常量池,StringBuffer为什么线程安全?加号的底层原理?
String类为什么是不可变的
-
String不可变的原因包括 设计考虑,效率优化问题,以及安全性这三大方面。
-
安全性:String被许多的Java类(库)用来当作参数,例如:网络连接地址URL,文件地址path…假若String不是固定不变的,将会引起各种安全隐患
-
优化:Java中String对象的哈希码被频繁地使用, 比如在hashMap 等容器中。
字符串不变性保证了hash码的唯一性,因此可以放心地进行缓存.这也是一种性能优化手段,意味着不必每次都去计算新的哈希码. 在String类的定义中有如下代码:
private int hash;// 用来缓存hashCode
-
优化:字符串常量池(String pool, String intern pool, String保留池) 是Java堆内存中一个特殊的存储区域, 当创建一个String对象时,假如此字符串值已经存在于常量池中,则不会创建一个新的对象,而是引用已经存在的对象。
StringBuilder和StringBuffer的区别
- StringBuilder是非线程安全的,StringBuffer是线程安全的
(即使碰到了需要线程安全的情景,也没必要用StringBuffer,因为stringbuffer的线程安全,仅仅是保证jvm不抛出异常顺利的往下执行而已,它可不保证逻辑正确和调用顺序正确。大多数时候,我们需要的不仅仅是线程安全,而是锁。)
字符串常量池
-
字符串常量池的设计思想
-
字符串的分配,和其他的对象分配一样,耗费高昂的时间与空间代价,作为最基础的数据类型,大量频繁的创建字符串,极大程度地影响程序的性能
-
JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化。
为字符串开辟一个字符串常量池,类似于缓存区。
创建字符串常量时,首先查看字符串常量池是否存在该字符串。
存在该字符串,返回引用实例,不存在,实例化该字符串并放入池。
-
实现的基础
实现该优化的基础是因为字符串是不可变的,可以不用担心数据冲突进行共享。
运行时实例创建的全局字符串常量池中有一个表,总是为池中每个唯一的字符串对象维护一个引用,这就意味着它们一直引用着字符串常量池中的对象,所以,在常量池中的这些字符串不会被垃圾收集器回收。
-
-
通过new操作符创建的字符串对象不指向字符串池中的任何对象,但是可以通过使用字符串的intern()方法来指向其中的某一个。
String s1 = "Hello";
String s2 = new StringBuffer("He").append("llo").toString();
String s3 = s2.intern();
StringBuffer为什么线程安全
-
首先String的不可变的,所以线程安全
-
StringBuffer和StringBuilder是可变的,但是StringBuffer的append操作是带有synchronized的,所以线程安全。
https://juejin.im/post/5ae6dc04f265da0ba351d3ff—synchronized详解