字节码解析String以及intern()方法

判断下面的例子

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的路上修行

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值