判断下面的例子
public class DemoClass {
public static void main(String[] args) throws Exception {
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);
}
}
答案,分别是 false,true,true
解析原因,先javap -v DemoClass.class
得到
0: ldc #2 // String a
2: astore_1
3: ldc #3 // String b
5: astore_2
6: ldc #4 // String ab
8: astore_3
可以看到s1和s2和s3,s3直接有编译器优化变成了ab。
接下来s4
9: new #5 // class java/lang/StringBuilder
12: dup
13: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V
16: aload_1
17: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
20: aload_2
21: 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 4
可以看到s4的复制,实际上是底层new了StringBuilder然后append最后在toString,并把对象地址给了s4 。
接下来s5
29: ldc #4 // String ab
31: astore 5
而s5是直接指向#4符号引用,最终还是执行了字符串ab。跟s3赋值时候的指令6: ldc #4
的符号引用一样。
接下来s6
33: aload 4
35: invokevirtual #9 // Method java/lang/String.intern:()Ljava/lang/String;
38: astore 6
可以看到调用的是s4的String.intern方法。那么intern方法在jdk1.8的解释如下:
public native String intern();
1.8,对于本身s4而言,若之前字符串常量池中不存在,则将该字符串加入串池中,并返回串池中的新的引用地址给s4,若存在,则做啥处理。对于s6而言,则永远就是串池中的引用。
所以通过分析,可以知道s3是指向字符串常量池的地址,s4之指向堆内存中StringBulider对象,s5与s3的符号引用都一样,最终都是指向字符串常量池的地址,s6无论串池中之前是否存在,都返回串池的地址。
因此,分别是false,true,true。
第二个问题,intern的顺序和版本
jdk1.8为例
顺序1
String s1 = "a";
String s2 = "b";
String s4 = s1+s2;
String s5 = "ab";
String s6 = s4.intern();
System.out.println(s4==s5);
System.out.println(s6==s5);
顺序2
String s1 = "a";
String s2 = "b";
String s4 = s1+s2;
String s6 = s4.intern();
String s5 = "ab";
System.out.println(s4==s5);
System.out.println(s6==s5);
此时,顺序只是String s5 = "ab";
位置不同
顺序1,分别为false和true;顺序2,分别为true和true。
原因:
其实上面已经提到过了,intern
方法
对于本身s4而言,若之前字符串常量池中不存在,则将该字符串加入串池中,并返回串池中的新的引用地址给s4,若存在,则做啥处理。对于s6而言,则永远就是串池中的引用。
但是1.6版本的时候,
无论之前字符串常量池中存不存在该字符串,都不会更新s4的引用。所以,2次都是false和true。
【完,喜欢就点个赞呗】
正在去BAT的路上修行