JVM学习笔记——内存结构篇( 七 )

StringTable字符串延迟加载在这里我们再次强调一下StringTable中元素的加载原则:

  • StringTable中的值只会加载一次,不会重复加载
  • 存放在常量池的值在运行时不会加载 , 只有在第一次运行时才会加载到StringTable中
我们采用一个简单程序来证明:
package cn.itcast.jvm.t1.stringtable;/** * 演示字符串字面量也是【延迟】成为对象的 */public class TestString {public static void main(String[] args) {int x = args.length;System.out.println(); // 字符串个数 2275System.out.print("1");System.out.print("2");System.out.print("3");System.out.print("4");System.out.print("5");System.out.print("6");System.out.print("7");System.out.print("8");System.out.print("9");System.out.print("0");System.out.print("1"); // 字符串个数 2285System.out.print("2");System.out.print("3");System.out.print("4");System.out.print("5");System.out.print("6");System.out.print("7");System.out.print("8");System.out.print("9");System.out.print("0");System.out.print(x); // 字符串个数 2285}}StringTable的intern功能介绍我们的intern的功能主要分为两个版本:
  • jdk1.6:将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有会把此对象复制一份 , 放入串池,会把串池中的对象返回
  • jdk1.8:将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有则放入串池, 会把串池中的对象返回
我们利用同样的代码来进行不同版本的介绍:
// 1.6版本package cn.itcast.jvm;public class Demo1_23 {public static void main(String[] args) {// 我们来仔细分析这个操作// 首先StringTable里面加入"a" , 然后堆里加上一个"a";然后StringTable里面加入"b" , 然后堆里加上一个"b"// 最后使用了toString方法 , 将"ab"放入堆中String s = new String("a") + new String("b");// StringTable=["a","b"]// 堆:new String("a")new String("b")new String("ab")// 将这个字符串对象尝试放入串池 , 如果有则并不会放入,如果没有则放入串池,会把串池中的对象返回// 目前s没有在StringTable中,所以将其复制一份放入StringTable,并将StringTable里面的"ab"返回回去// 这时s和StringTable里面的"ab"是不一样的!String s2 = s.intern();// 这时x,s2是StringTable里面的"ab",s是堆里面的"ab"String x = "ab";System.out.println( s2 == x);//trueSystem.out.println( s == x );//false}}public static void main(String[] args) {String x = "ab";String s = new String("a") + new String("b");// StringTable=["a","b","ab"]// 堆new String("a")new String("b") new String("ab")// 将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有则放入串池,会把串池中的对象返回// 目前StringTable里存在"ab",所以将StringTable里面的ab返回给s2即可// 目前s2和x属于StringTable里面的ab,s属于堆里面的abString s2 = s.intern();System.out.println( s2 == x);//trueSystem.out.println( s == x );//false}}// 1.8版本package cn.itcast.jvm.t1.stringtable;public class Demo1_23 {public static void main(String[] args) {String s = new String("a") + new String("b");// StringTable=["a","b"]// 堆new String("a")new String("b") new String("ab")// 将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有则放入串池,会把串池中的对象返回// 这里由于StringTable里面不存在,会将堆中s的字符串做成一个引用直接放入StringTable里面 , 再将StringTable的值返回// 这时s , s2,x均属于堆里面的ab,不过s2是堆里的ab,s,x为StringTable里面的引用的堆里面的ab,但他们相等String s2 = s.intern();String x = "ab";System.out.println( s2 == x);//trueSystem.out.println( s == x );//true}}public static void main(String[] args) {String x = "ab";String s = new String("a") + new String("b");// StringTable=["a","b","ab"]// 堆new String("a")new String("b") new String("ab")// 将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有则放入串池,会把串池中的对象返回// 目前StringTable里存在"ab",所以将StringTable里面的ab返回给s2即可// 目前s2和x属于StringTable里面的ab,s属于堆里面的abString s2 = s.intern();System.out.println( s2 == x);//trueSystem.out.println( s == x );//false}}StringTable常见面试题解答下面我们给出一个StringTable的常见面试题来进行测试:
package cn.itcast.jvm.t1.stringtable;/** * 演示字符串相关面试题 */public class Demo1_21 {// 我们会给出StringTable和堆的值public static void main(String[] args) {// StringTable=["a"]String s1 = "a";// StringTable=["a","b"]String s2 = "b";// StringTable=["a","b","ab"]String s3 = "a" + "b"; // ab// StringTable=["a","b","ab"],堆:"ab"String s4 = s1 + s2;// new String("ab") 和 s3 不相等// StringTable=["a","b","ab"],堆:"ab"String s5 = "ab"; // s3 == s5// StringTable=["a","b","ab"],堆:"ab"String s6 = s4.intern(); // s4是堆里的ab,s6是StringTable里面的ab// 问System.out.println(s3 == s4); // falseSystem.out.println(s3 == s5); // trueSystem.out.println(s3 == s6); // true// StringTable=["a","b","ab" , "c","d"],堆:"ab"."c","d","cd"String x2 = new String("c") + new String("d"); // new String("cd")// StringTable=["a","b" , "ab" , "c","d","cd-来自堆"],堆:"ab"."c","d","cd"x2.intern();// x1是StringTable里面的cd , 但StringTable里面的cd来自堆,所以x1 == x2String x1 = "cd";System.out.println(x1 == x2);// 问 , 如果调换了【最后两行代码】的位置呢 , 如果是jdk1.6呢(这个就自己思考啦~)}}

推荐阅读