本文主要是介绍常量池和StringTable,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
1 运行时常量池
常量池,就是一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量等信息
运行时常量池,常量池是 *.class 文件中的,当该类被加载,它的常量池信息就会放入运行时常量池,并把里面的符号地址变为真实地址
2 StringTable(串池)
先看一道面试题:
String s1 = "a";
String s2 = "b";
String s3 = "a" + "b";
String s4 = s1 + s2;
String s5 = "ab";
String s6 = s4.intern();
// 问
System.out.println(s3 == s4);
System.out.println(s3 == s5);
System.out.println(s3 == s6);
String x2 = new String("c") + new String("d");
String x1 = "cd";
x2.intern();
// 问,如果调换了【最后两行代码】的位置呢,如果是jdk1.6呢
System.out.println(x1 == x2);
答案是:false true true false(调换后true)
上面程序使用javap -v反编译后得到JVM指令如下:
public static void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)Vflags: ACC_PUBLIC, ACC_STATICCode:stack=4, locals=9, args_size=10: ldc #2 // String a2: astore_13: ldc #3 // String b5: astore_26: ldc #4 // String ab8: astore_39: new #5 // class java/lang/StringBuilder12: dup13: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V16: aload_117: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;20: aload_221: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;24: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;27: astore 429: ldc #4 // String ab31: astore 533: aload 435: invokevirtual #9 // Method java/lang/String.intern:()Ljava/lang/String;38: astore 640: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream;43: aload_344: aload 446: if_acmpne 5349: iconst_150: goto 5453: iconst_054: invokevirtual #11 // Method java/io/PrintStream.println:(Z)V57: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream;60: aload_361: aload 563: if_acmpne 7066: iconst_167: goto 7170: iconst_071: invokevirtual #11 // Method java/io/PrintStream.println:(Z)V74: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream;77: aload_378: aload 680: if_acmpne 8783: iconst_184: goto 8887: iconst_088: invokevirtual #11 // Method java/io/PrintStream.println:(Z)V91: new #5 // class java/lang/StringBuilder94: dup95: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V98: new #12 // class java/lang/String101: dup102: ldc #13 // String c104: invokespecial #14 // Method java/lang/String."<init>":(Ljava/lang/String;)V107: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;110: new #12 // class java/lang/String113: dup114: ldc #15 // String d116: invokespecial #14 // Method java/lang/String."<init>":(Ljava/lang/String;)V119: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;122: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;125: astore 7127: ldc #16 // String cd129: astore 8131: aload 7133: invokevirtual #9 // Method java/lang/String.intern:()Ljava/lang/String;136: pop137: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream;140: aload 8142: aload 7144: if_acmpne 151147: iconst_1148: goto 152151: iconst_0152: invokevirtual #11 // Method java/io/PrintStream.println:(Z)V155: return
分析:
s1引用的是串池中的常量"a"
s2引用的是串池中的常量"b"
s3引用的是编译时优化的"a"“b"拼接后的串池中的常量"ab”
s4引用的是堆中StringBuilder对象调用init方法初始化,并append"a",又append"b",最后调用toString得到的String对象
s5引用的是串池中的常量"ab"
s6,由于s4的对象内容"ab"在s3执行时就已经入池,因此返回串池中的"ab",即s3的地址
x2引用的是堆中StringBuilder对象调用init方法初始化,并append堆中创建的"c"和"d"String对象,最后调用toString得到的String对象
x1引用的是串池中的常量"cd"
x2.intern();执行完上一句后,此时串池中已有"cd",不会将x2放入串池,x2仍引用堆中的对象地址
注意1:若执行x2.intern();后再String x1 = “cd”;则两个变量引用的都是串池中的"cd"的地址
注意2:以上都是jdk1.8版本的答案,如果是jdk1.6,在String x2 = new String(“c”) + new String(“d”);后,先执行x2.intern();再String x1 = “cd”;分析为:x2.intern()将堆中对象拷贝到串池中,导致x1==x2结果为false
intern方法说明:
功能:将串池中还没有的字符串对象放入串池
1.8 将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有则放入串池, 会把串池中的对象返回
1.6 将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有会把此对象复制一份,放入串池, 会把串池中的对象返回
StringTable总结
位置 | GC | 调优 |
---|---|---|
1.8版本位于堆中 1.6版本只存在于老年代 | 1.8时触发minorGC 1.6时触发fullGC | 增大堆内存的同时 适当增加StringTableSize桶个数可以减少寻址时的hash碰撞概率,从而节省读写时间 intern方法使对象入池复用(大量重复情况),可以节省大量创建新对象占用堆内存 |
这篇关于常量池和StringTable的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!