Java-String详解


1. String的基本特性

String:字符串,使用一对""进行表示

String s1 = "atguigu";//字面量定义方式
String s2 = new String("");

String是不可被继承的,设置为final, 其底层是char[],而在JDK1.9之后,使用了byte[]数组

为什么要修改成byte[]数组?这是为了更好的节省空间,当使用char[]数组的时候,一个char就是16个bit,而言对于大部分的拉丁文字来说,他们只需要1个字节就能存储,因此为了因地制宜地使用这个字符编码,采用byte[]来存储原始数据,当需要解析数据的时候才使用具体的字符解码规则。

如何来看这个表?ldc #2,他说的是要到常量池中查找#2的这个信息,记载好信息之后,将这个信息加载到s3变量中去,它类似于一个槽,可以将一个变量存到这个槽中。

这就是运行时常量池的样子,可与会看到,此时a,b,ab都是常量池中的符号

当执行代码ldc #2的时候,就会将这个符号变为一个对象,StringTable[]

此时会去检查StringTable[]是否有这个对象,如果没有这个对象,那么就会将a加入这个table,也就是StringTable["a"]

因此,可以看出不是一开始就将这个字符串放入这个StringTable的,而是在执行到相应的代码之后,才会将这个字符串加载到StringTable中去,有一种懒加载的思想,称为字符串的的延迟加载

String s1 = "a";
String s2 = "b";
String s3 = "ab";
String s4 = s1+s2;//new StringBuilder().append("a").append("b").toString(),它就相当于new String("ab"),这个对象并不会加入到常量池中,相当于是动态拼接的
String s5 = "a" + "b"; 

关于s5的结果,要从编译优化的结果来看,s5所产生的结果是"a"+"b",编译器在读取到这个式子的时候,发现都是常量的加减,因此就会在编译期间将这个结果修改为"ab",那么你就会发现,由于之前执行ldc #3的时候,就已经将ab加入了常量池,那么在s5的时候,它就不会再去创建新对象,而是将之前加入了Table中对象拿过来使用

关于StringTable

常量池中的字符串仅仅只是符号,在第一次使用的时候才变为对象

利用串池的机制,来避免重复地创建字符串对象

字符串变量拼接的原理是StringBuilder

字符串常量拼接的原理的是编译器优化

可以将intern()方法,主动将串池中还没有的字符串放入串池

String s = new String("a")+new String("b");
//堆 new String("a"), new String("b") new String("ab")
String s2 = s.intern();//将这个字符串对象尝试放入到串池,如果有的话那么就不会放入,没有的话就会放入串池,会把串池中的对象返回

StringTable的位置

1.6中的StringTable是放在永久代中的,而1.8中的StringTable是放在堆中的

2. 如何理的解String的不可变?

当对字符串进行重新赋值的时候,需要重新堆内存中的字符串常量池,不能够使用原来的value进行赋值

当对现有的字符串进行连接操作的时候,也是需要重新申请内存,然后创建新的字符串的,不能使用原有的value进行赋值

当使用Stringreplace()方法修改指定字符或者字符串的时候,也需要重新指定内存区域赋值,不能够使用原有的value进行赋值

通过字面量的方式给一个字符串赋值,此时字符串的声明在字符串的常量池中


文章作者: 穿山甲
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 穿山甲 !
  目录