String在jdk9中底层不再使用char型数组,而是使用byte型数组,因为在实际开发中发现大多数字符串中存储的都是Lantin-1(每个字符一个字节),这些字符只需要1byte的空间就可以存储。
看 6. JVM 方法区的3.1
注意:只有字符串变量在拼接的时候调用的才是StringBuilder,如果是final修饰的变量,则是编译期优化
public void test2() { final String a = "abcdef"; final String b = "abc"; final String c = "def"; String d = b + c; //b + c在编译期间就被优化成为了 "abcdef" System.out.println(d == a); //true } 如果不是用双引号声明的String对象,可以使用String提供的intern方法:inter方法会从字符串常量池中查询当前字符串是否存在,若存在,返回已有的串池中对象的地址;若不存在,会把对象的引用地址复制一份,放入串池,并返回串池中的引用地址。
intern 就是确保字符串在内存里只有一份拷贝,这样可以节约空间,加快字符串操作任务的速度。
new String(“ab”) 会创建2个对象
new String本身字符串常量池中的abnew String(“a”) + new String(“b”) 会创建5个对象
StringBuildernew String(“a”)常量池中的anew String(“b”)常量池中的b练习一
public void test4() { String s = new String("1"); //在堆空间中创建了String对象,在常量池中创建了“1” String s1 = s.intern(); String s2 = "1"; System.out.println(s == s1); //false,s指向堆空间中的String对象,s1指向常量池中的 “1” System.out.println(s1 == s2); //true,s2也指向常量池中的“1” }练习二
public void test5() { String s3 = new String("1") + new String("1"); //此时字符串常量池中只有 “1”,而没有 “11” s3.intern(); //jdk7开始,常量池中并没有创建“11”,而是创建一个指向堆空间中 new String("11")的地址 String s4 = "11"; //s4变量记录的地址:指向堆空间中 new String("11")的地址 System.out.println(s3 == s4); //jdk6:false,jdk7/8:true }练习三
public void test6() { String s5 = "11"; String s6 = new String("1") + new String("1"); String s7 = s6.intern(); System.out.println(s5 == s6); //false,因为“11”已经先创建了,所以调用s6.intern后,并不会在常量池中创建指向s5地址的项 System.out.println(s5 == s7); //true }