注:本专栏文章均为自己原创,未经自己授权请勿私自转载,谢谢。
以下是源代码剖析:
public static void main(String[] args) {
// 初始化时常量池无该字符串缓存,则在常量池创立一个实例;同时,new 操作符在堆内存也创立一个实例;
String str1 = new String("ABCDEFG");
String str2 = "ABCDEFG"; // 直接从常量池中查找,不创立
String str3 = "ABCDEFG"; // 直接从常量池中查找,不创立
System.out.println(str2 == str3); // true
System.out.println(str1 == str2); // false
System.out.println(str1.equals(str2)); // true
System.out.println(51 == 51.0); // 根本类型比较值
}
以下是字节码剖析:
【说明】:有些操作符后边带有#n,这是在Constant Pool中所分配的序号,主要是为了削减网络传输的流量和时刻,故用序号替代。
0: new #2 <java/lang/String> // new 一个 String 类型的目标
3: dup // 仿制类实例引证并压入栈顶(标记为待处理)
4: ldc #3 <ABCDEFG> // 将字符串从常量池加载到操作数栈(由于该类的构造函数中传入了 ABCDFEG 常量,此刻常量池中的字符串已创立,故需要从常量池加载)
6: invokespecial #4 <java/lang/String.<init>> // 履行构造方法
9: astore_1 // 将该值存为变量 1
10: ldc #3 <ABCDEFG> // 直接从常量池加载 ABCDFEG 常量
12: astore_2 // 将该值存为变量 2
13: ldc #3 <ABCDEFG> // 直接从常量池加载 ABCDFEG 常量
15: astore_3 // 将该值存为变量 3
// 从这儿开端是第一个比较逻辑
16: getstatic #5 <java/lang/System.out>
19: aload_2
20: aload_3
21: if_acmpne 28 (+7) // 若变量 2 和变量 3 持平,则继续履行,不然跳到 28
24: iconst_1 // 持平时:加载变量 1(true)
25: goto 29 (+4) // 跳到 29
28: iconst_0 // 不持平时:加载变量 0(false)
29: invokevirtual #6 <java/io/PrintStream.println> // 打印该变量
// 从这儿开端是第二个比较逻辑,与上个相仿,就不做评论了
32: getstatic #5 <java/lang/System.out>
35: aload_1
36: aload_2
37: if_acmpne 44 (+7)
40: iconst_1
41: goto 45 (+4)
44: iconst_0
45: invokevirtual #6 <java/io/PrintStream.println>
48: getstatic #5 <java/lang/System.out>
51: aload_1
52: aload_2
53: invokevirtual #7 <java/lang/String.equals>
56: invokevirtual #6 <java/io/PrintStream.println>
// 从这儿开端是最终的数字比较,能够看到 Java 直接将 结果优化成了 true
59: getstatic #5 <java/lang/System.out>
62: iconst_1
63: invokevirtual #6 <java/io/PrintStream.println>
66: return
别的,对于以下代码,strRes1和strRes2的反编译代码天壤之别:
public static void main(String[] args) {
/*final*/ String str1 = "abc";
/*final*/ String str2 = "def";
String strRes1 = "abc" + "def"; // String strRes1 = "abcdef";
String strRes2 = str1 + str2; // String strRes2 = new StringBuilder().append(str1).append(str2).toString();
System.out.println(strRes1 + ":" + strRes2);
}
当某字符串等于两字符串常量相加时,java编译器会将其主动优化为两个字符串常量的和;而当某字符串等于两字符串变量相加时,java编译器不会进行优化。
也就是,当str1和str2都为final类型的字符串时,strRes2的反编译代码也会变为String strRes2 = "abcdef";
。