注:本专栏文章均为自己原创,未经自己授权请勿私自转载,谢谢。

以下是源代码剖析:

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";