用javap命令反编译来分析字符串问题

编写Test.java,编译完后生成Test.class文件,然后对该文件执行javap -c Test命令,生成字节码指令,阅读并得出结论
一、s1和s2指向常量池的不同常量
①java代码
public class Test {
    public static void main(String[] args) throws IOException {
        String s1="t";
        String s2="m";
    }
}
②反编译可以看到字节码指令执行如下:
Compiled from "Test.java"
public class typ.Test extends java.lang.Object{
public typ.Test();
  Code:
   0:   aload_0
   1:   invokespecial   #8//Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[])   throws java.io.IOException;
  Code:
   0:   ldc     #19//String t 进入操作数栈顶
   2:   astore_1     //String t 出操作数栈,赋值给变量1,即s1
   3:   ldc     #21//String m 进入操作数栈顶
   5:   astore_2     //String m 出操作数栈,赋值给变量2,即s2
   6:   return
}
从上面可以看出,两次ldc入栈操作分别指向的是常量#19和#21

二、s1和s2指向常量池的相同常量
①java代码
public class Test {
    public static void main(String[] args) throws IOException {
        String s1="t";
        String s2="t";
    }
}
②反编译可以看到字节码指令执行如下:
Compiled from "Test.java"
public class typ.Test extends java.lang.Object{
public typ.Test();
  Code:
   0:   aload_0
   1:   invokespecial   #8//Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[])   throws java.io.IOException;
  Code:
   0:   ldc     #19//String t 进入操作数栈顶
   2:   astore_1     //String t 出操作数栈,赋值给变量1,即s1
   3:   ldc     #19//String t 进入操作数栈顶
   5:   astore_2     //String t 出操作数栈,赋值给变量2,即s2
   6:   return
}
从上面可以看出,两次ldc入栈的操作数都是将指向的常量#19,所以可以看出是s1和s2都是指向常量池的同一个常量“t”

三、进一步看下面
①java代码
public class Test {
    public static void main(String[] args) throws IOException {
        String s1="tm";
        String s2="t"+"m";
    }
}
反编译可以看到字节码指令执行如下:
Compiled from "Test.java"
public class typ.Test extends java.lang.Object{
public typ.Test();
  Code:
   0:   aload_0
   1:   invokespecial   #8//Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[])   throws java.io.IOException;
  Code:
   0:   ldc     #19//String tm 进入操作数栈顶
   2:   astore_1     //String tm 出操作数栈,赋值给变量1,即s1
   3:   ldc     #19//String tm 进入操作数栈顶
   5:   astore_2     //String tm 出操作数栈,赋值给变量2,即s2
   6:   return
}
可以看出,两次ldc(load命令, 将操作数入栈)入栈的 操作数都是将指向的常量#19即“tm”,说明在编译期间,“t”+"m"就已经变为“tm”这一个常量了

四、再进一步
①java代码
public class Test {
    public static void main(String[] args) throws IOException {
        String tmp = "t";
        String s1 = "m";
        String s2 = tmp + "m";
    }
}
反编译可以看到字节码指令执行如下:
Compiled from "Test.java"
public class typ.Test extends java.lang.Object{
public typ.Test();
  Code:
   0:   aload_0
   1:   invokespecial   #8//Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[])   throws java.io.IOException;
  Code:
   0:   ldc     #19//String t 进入操作数栈顶
   2:   astore_1     //String t 出操作数栈,赋值给变量1,即tmp
   3:   ldc     #21//String m 进入操作数栈顶
   5:   astore_2     //String m 出操作数栈,赋值给变量2,即s1
   6:   new     #23//class java/lang/StringBuilder 创建StringBuilder类型对
 
   9:   dup           // 复制栈顶一个字长的数据,将复制后的数据压栈  
   10:  aload_1      //tmp 进入操作数栈顶
   11:  invokestatic    #25//Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
   14:  invokespecial   #31//Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
   17:  ldc     #21//String m
   19:  invokevirtual   #34//Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   22:  invokevirtual   #38//Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   25:  astore_3
   26:  return
}

从上面的代码可以看出,string的相加要通过stringbuilder,并且由于tmp是变量,所以调用的 invokevirtual指令(在编译器无法确定),这说明不是
在编译期 完成,因此s1 与s2时不相等的

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值