String以及StringTable复盘
String有两种实例化的方式:
- String s1 = “atguigu”; //字面量的定义方式
- String s2 = new String(“hello”);
jdk8和jdk9中String底层变化
- jdk8中String底层是用final修饰的char数组。
- jdk9中是用final修饰byte数组。
为什么要做出这样的修改呢?
因为大部分字符串都是拉丁字符,而拉丁字符只需要一个字节就可以了,而中文需要两个字节。以前统一用char就会浪费内存,而现在只需要增加一个标志位,如果是拉丁字符就用一个字节,如果是其他复杂字符就用两个字节。节省了空间。
StringTableSize的长度
在jdk6中默认是1009,且可以修改。
在jdk7中默认是60013。
在jdk8中,1009是可以设置的最小值。
String的内存分配
Java中有8中基本数据类型,和一种比较特殊的类型String。
jdk6及以前,字符串常量池存放在永久代中。jdk7以后,字符串常量池调整到了堆中,
常量与常量的拼接结果是在常量池
String s = "a"+"b"+"c";//等同于String s = "abc";字符串常量表中也只有"abc"(会进行一个编译器优化)
//字符串拼接不一定会用StringBuilder,也可能拼接的字符串常量,那么就会进行编译器优化
只要拼接字符串里有一个是变量,相当于在堆空间中new String()。结果就在堆中。变量拼接的原理是StringBuilder
intern():判断字符串常量池中是否存在某个字符串,如果存在,则返回常量池中字符串值得地址,如果字符串常量池中不存在,则在常量池中加载一份,并返回此对象的地址。
jdk7及以后,intern方法。
String s1 = new String("1")+new String("1"); s1.intern(); String s2 = "11"; System.out.println(s1==s2);//jdk7及以后true,jdk6为false
因为s1.intern()方法,取字符串常量池中放11时,没找到"11",为了节省空间,就把字符串常量池中的"11"指向了堆中的new出的"11";