编写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: returnpublic 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: returnpublic 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: returnpublic 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: returnpublic 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时不相等的