package design.wlb.studyjava.demo.restudy.c4jvm专题.chapter02.c30StringTable编译期优化;
public class Client {
//我们通过new关键字创建的堆对象,都会使用堆的内存。
//jdk1.6中,StringTable串池在常量池在方法区中,jdk1.8中,常量池在元空间不归jvm管理,但串池不在常量池中,是在堆中。
//StringTable["a","b","ab"](懒加载)
public static void main(String[] args) {
String s1 = "a"; //ldc #2 astore_1 从常量池加载为java字符串常量对象,将这个对象放入串池中,并存储到局部变量表的1号位置。
String s2 = "b";
String s3 = "ab";
String s4 = s1 + s2;
String s5 = "a"+"b"; //javac编译器优化,在编译时,直接认为此为固定的常量 "ab" ,故而反编译后的指令为ldc #4 astore 5 存入到第五个局部变量表中
System.out.println(s5==s3);
//s4在非串池的其他堆中,s5在串池中。
}
}
由我们的javap反编译工具可知,
String s5 = "a"+"b";
在jvm指令对应的是"ldc #4", 以及astore 5
它和我们想象的有点区别,它并不是使用的StringBuilder进行字符串拼接了,因为此处"a"+"b",两者都是字符串常量,在javac编译期,jdk就认识它只会是"ab".故而,进行了java编译期优化,在生成的class文件后,就已经变成了String s5 = "ab";
所以它的加载方式也和s3一模一样。ldc #4 astore 5,从运行时常量池中取出"ab",然后存入局部变量表的5号位置【astore aload 是一对操作局部变量表的jvm指令】
也就是说,jvm从运行期常量池查表#4的位置获取将其变为java对象"ab",再将java字符串常量对象"ab"放入串池(另一个堆区),但放入串池中的时候会去查串池中的key 有不有,此时因为有了String s3 = "ab",串池中已经有了"ab",所以jvm直接从串池中查表找到了它。
所以s3和s5都是从串池中获取值,故而s3 == s5 答案是false;
补充:
1.串池也叫字符串常量池
2.串池可以理解为逻辑上在运行期常量池里面(jdk1.6在永久代里面,物理上也是在运行常量池中,jdk1.8运行期常量池在元空间里面,但串池逻辑上在,但物理上是存在jvm的堆中)
好,这一篇就讲到这里。
上一篇:29.jvm内存结构部分——StringTable_字符串变量的拼接_tgbyhn31的博客-CSDN博客
下一篇:31.jvm内存结构部分——StringTable字符串延迟加载_tgbyhn31的博客-CSDN博客



