概览
String 被声明为 final,所以它不可被继承。(Integer 等包装类也不能被继承)数组
在 Java 8 中,String 内部使用 char 数组存储数据。缓存
在 Java 9 以后,String 类的实现改用 byte 数组存储字符串,同时使用 coder
来标识使用了哪一种编码。安全
value 数组被声明为 final,这意味着 value 数组初始化以后就不能再引用其它数组。而且 String 内部没有改变 value 数组的方法,所以能够保证 String 不可变。网络
不可变的好处
能够缓存 hash 值
由于 String 的 hash 值常常被使用,例如 String 用作 HashMap 的 key。不可变的特性可使得 hash 值也不可变,所以只须要进行一次计算。ui
String Pool 的须要
若是一个 String 对象已经被建立过了,那么就会从 String Pool 中取得引用。只有 String 是不可变的,才可能使用 String Pool。编码
安全性
String 常常做为参数,String 不可变性能够保证参数不可变。例如在做为网络链接参数的状况下若是 String 是可变的,那么在网络链接过程当中,String 被改变,改变 String 对象的那一方觉得如今链接的是其它主机,而实际状况却不必定是。spa
线程安全
String 不可变性天生具有线程安全,能够在多个线程中安全地使用。线程
String VS StringBuffer VS StringBuilder
可变性
- String 不可变
- StringBuffer 和 StringBuilder 可变
线程安全
- String 不可变,所以是线程安全的
- StringBuilder 不是线程安全的
- StringBuffer 是线程安全的,内部使用 synchronized 进行同步
String Pool
字符串常量池(String Pool)保存着全部字符串字面量(literal strings),这些字面量在编译时期就肯定。不只如此,还可使用 String 的 intern() 方法在运行过程当中将字符串添加到 String Pool 中。code
当一个字符串调用 intern() 方法时,若是 String Pool 中已经存在一个字符串和该字符串值相等(使用 equals() 方法进行肯定),那么就会返回 String Pool 中字符串的引用;不然,就会在 String Pool 中添加一个新的字符串,并返回这个新字符串的引用。对象
下面示例中,s1 和 s2 采用 new String() 的方式新建了两个不一样字符串,而 s3 和 s4 是经过 s1.intern() 方法取得一个字符串引用。intern() 首先把 s1 引用的字符串放到 String Pool 中,而后返回这个字符串引用。所以 s3 和 s4 引用的是同一个字符串。
若是是采用 如下这种字面量的形式建立字符串,会自动地将字符串放入 String Pool 中。
在 Java 7 以前,String Pool 被放在运行时常量池中,它属于永久代。而在 Java 7,String Pool 被移到堆中。这是由于永久代的空间有限,在大量使用字符串的场景下会致使 OutOfMemoryError 错误。
new String("xxx")
使用这种方式一共会建立两个字符串对象(前提是 String Pool 中尚未 "xxx" 字符串对象)。
- 执行语句String str="xxx";时。首先查看字符串池中是否存在字符串"xxx",若是存在则直接将“xxx”赋给str,若是不存在则先在 字 符串池中新建一个字符串"xxx",而后再将其赋给str.
- new 建立字符串时,首先查看池中是否有相同的字符串,若是有则拷贝一份放到堆中,而后返回堆中的地址;若是池中没有则在堆中建立一分,而后返回堆中的地址,