简介
jdk8及以前底层用char[]数组实现,jdk9以后改为byte[]。
jdk6及以前,字符串常量池存放在永久代。jdk7及其以后保存在Java堆中。
不可变性
对String字符串重新赋值,拼接,replace指定字符,都不能使用原有value进行赋值。
字符串拼接结果保存
- 两个常量拼接结果在常量池,原理是编译器优化。
- 要是拼接表达式存在变量,结果就保存在堆中。底层使用String Builder拼接。
- 如果拼接结果调用intern()方法,则主动将常量池中还没有的字符串对象存入常量池中,并返回此对象地址。
intern()
图示
代码演示
1 | /** |
字符串常量池
String 的String Pool 不存在相同的内容变量,是固定大小的HashTable,默认长度1009,当里面String过多时,Hash冲突严重,导致链表会很长,String.itern(用于将字符串放入常量池)性能严重下降。
JVM参数
-XX: StringTableSize 可设置JVM的StringTable长度。
- jdk6:StringTable固定大小,长度就是1009。
- jdk7:长度默认60013。
- jdk8:长度默认60013。1009是设置String Table的最小值。
问题!!!
new String(“ab”);new String(“a”) + new String(“b”); 分别创建多少个对象?
new String(“ab”);
两个:
一个是堆中new出来的对象,一个是常量池中的”ab”字符串。
new String(“a”) + new String(“b”);
六个:
- StringBulider对象
- new String(“a”)堆中new对象
- 常量池中的”a”字符串
- new String(“b”)堆中new对象
- 常量池中的”b”字符串
- StringBuilder的toString()方法返回new String(“ab”).注:调用toString()方法常量池不会生成字符串”ab”
扩展String、StringBuilder、StringBuffer区别
String底层是用final修饰的char数组,不可改变,(String的大部分情况都是字母,一个字节即可满足,为降低内存占用,jdk9后改成byte数组,StringBuilder和StringBuffer也是,并用coder字段修饰编码类型)。
1 | //coder字段可选值 |
StringBuilder底层是一个可变的char数组,默认初始化长度为16,构造器有字符串传参时默认长度为字符串长度+16,append操作超过原有长度限制时以下规则扩展。
1 | private int newCapacity(int minCapacity) { |
StringBuffer使用synchronized修饰方法,线程安全,内部维护一个char[] toStringCache数组缓存最近一次toString()的值,每次修改前都置为null。扩展规则和StringBuilder一致,都是使用AbstractStringBuilder抽象类的方法。
1 |
|