Java final关键字如何处理字符串不变性?

Java final关键字如何处理字符串不变性?,java,string,Java,String,我有以下代码。我理解java字符串不变性和字符串常量池的概念。我不明白为什么在下面的程序中'name1==name2'结果为false而'name2==name3'结果为true。字符串变量name1、name2和name3如何放置在字符串常量池中 public class Test { public static void main(String[] args) { final String firstName = "John"; S

我有以下代码。我理解java字符串不变性和字符串常量池的概念。我不明白为什么在下面的程序中'name1==name2'结果为false而'name2==name3'结果为true。字符串变量name1、name2和name3如何放置在字符串常量池中

public class Test {
    public static void main(String[] args) {
        final String firstName = "John";
        String lastName = "Smith";
        String name1 = firstName + lastName;
        String name2 = firstName + "Smith";
        String name3 = "John" + "Smith";
        System.out.println(name1 == name2);
        System.out.println(name2 == name3);
   }
}

Output:
false
true

让我们看一下带有
final
的字节码:

公共类测试{
公开考试();
代码:
0:aload_0
1:invokespecial#1//方法java/lang/Object。“:()V
4:返回
公共静态void main(java.lang.String[]);
代码:
0:ldc#7//String Smith
2:astore_1
3:aload_1
4:invokedynamic#9,0//invokedynamic#0:makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;
9:astore_2
10:ldc#13//String JohnSmith
12:astore_3
13:ldc#13//String JohnSmith
15:astore 4
17:getstatic#15//fieldjava/lang/System.out:Ljava/io/PrintStream;
20:aload_2
21:aload_3
22:if_acmpne 29
25:iconst_1
26:goto 30
29:iconst_0
30:invokevirtual#21//方法java/io/PrintStream.println:(Z)V
33:getstatic#15//fieldjava/lang/System.out:Ljava/io/PrintStream;
36:aload_3
37:aload 4
39:if_acmpne 46
42:iconst_1
43:转到47
46:iconst_0
47:invokevirtual#21//方法java/io/PrintStream.println:(Z)V
50:返回
}
以及不带
final
的字节码:

公共类测试{
公开考试();
代码:
0:aload_0
1:invokespecial#1//方法java/lang/Object。“:()V
4:返回
公共静态void main(java.lang.String[]);
代码:
0:ldc#7//String John
2:astore_1
3:ldc#9//String Smith
5:astore_2
6:aload_1
7:aload_2
8:invokedynamic#11,0//invokedynamic#0:makeConcatWithConstants:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
13:astore_3
14:aload_1
15:invokedynamic#15,0//invokedynamic#1:makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;
20:astore 4
22:ldc#18//String JohnSmith
24:astore 5
26:getstatic#20//Field java/lang/System.out:Ljava/io/PrintStream;
29:aload_3
30:aload 4
32:if_acmpne 39
35:iconst_1
36:goto 40
39:iconst_0
40:invokevirtual#26//方法java/io/PrintStream.println:(Z)V
43:getstatic#20//fieldjava/lang/System.out:Ljava/io/PrintStream;
46:aload 4
48:aload 5
50:if_acmpne 57
53:iconst_1
54:转到58
57:iconst_0
58:invokevirtual#26//方法java/io/PrintStream.println:(Z)V
61:返回
}
如您所见,使用
final
,Java将
+
的左侧和右侧都识别为常量,因此它在编译时用常量字符串
“JohnSmith”
替换了串联。对
makeConcatWithConstants
(连接字符串)的唯一调用是针对
firstName+lastName
,因为
lastName
不是最终的

在第二个示例中,有两个调用
makeConcatWithConstants
,一个调用
firstName+lastName
,另一个调用
firstName+“Smith”
,因为Java不将
firstName
识别为常量


这就是为什么在您的示例中
name1==name2
false
name2
是字符串池中的常量
“JohnSmith”
,而
name1
是在运行时动态计算的。但是,
name2
name3
都是字符串池中的常量,这就是为什么
name2==name3
true
让我们看看带有
final
的字节码:

公共类测试{
公开考试();
代码:
0:aload_0
1:invokespecial#1//方法java/lang/Object。“:()V
4:返回
公共静态void main(java.lang.String[]);
代码:
0:ldc#7//String Smith
2:astore_1
3:aload_1
4:invokedynamic#9,0//invokedynamic#0:makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;
9:astore_2
10:ldc#13//String JohnSmith
12:astore_3
13:ldc#13//String JohnSmith
15:astore 4
17:getstatic#15//fieldjava/lang/System.out:Ljava/io/PrintStream;
20:aload_2
21:aload_3
22:if_acmpne 29
25:iconst_1
26:goto 30
29:iconst_0
30:invokevirtual#21//方法java/io/PrintStream.println:(Z)V
33:getstatic#15//fieldjava/lang/System.out:Ljava/io/PrintStream;
36:aload_3
37:aload 4
39:if_acmpne 46
42:iconst_1
43:转到47
46:iconst_0
47:invokevirtual#21//方法java/io/PrintStream.println:(Z)V
50:返回
}
以及不带
final
的字节码:

公共类测试{
公开考试();
代码:
0:aload_0
1:invokespecial#1//方法java/lang/Object。“:()V
4:返回
公共静态void main(java.lang.String[]);
代码:
0:ldc#7//Stri
class BatchOConstants {
    public static final int HELLO = 5;
}

public class UserOfBatch {
    public static void main(String[] args) {
        System.out.println(BatchOConstants.HELLO);
    }
}
> javac UserOfBatch.java
> java UserOfBatch
5
> javap -c UserOfBatch # javap prints bytecode
 public static void main(java.lang.String[]);
    Code:
       0: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: iconst_5
       4: invokevirtual #15                 // Method java/io/PrintStream.println:(I)V
       7: return
> rm BatchOConstants.class
> java UserOfBatch
5
public @interface Foo {
    long value();
    public Main() {
        final String a = "hello";
        String b = "world";
        String c = a + "!";
        String d = b + "!";
        System.out.println(c == "hello!");
        System.out.println(d == "world!");
    }
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: ldc           #7                  // String hello
         6: astore_1
        start local 1 // java.lang.String a
         7: ldc           #9                  // String world
         9: astore_2
        start local 2 // java.lang.String b
        10: ldc           #11                 // String hello!
        12: astore_3
        start local 3 // java.lang.String c
        13: aload_2
        14: invokedynamic #13,  0             // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;
        19: astore        4
        start local 4 // java.lang.String d
Compiled from "Test.java"                                                                                                     
public class Test {                                                                                                           
  public Test();                                                                                                              
    Code:                                                                                                                     
       0: aload_0                                                                                                             
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V                                           
       4: return                                                                                                              
                                                                                                                              
  public static void main(java.lang.String[]);                                                                                
    Code:                                                                                                                     
       0: ldc           #2                  // String Smith                                                                   
       2: astore_2                                                                                                            
       3: aload_2                                                                                                             
       4: invokedynamic #3,  0              // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;
       9: astore_3                                                                                                            
      10: ldc           #4                  // String JohnSmith                                                               
      12: astore        4                                                                                                     
      14: ldc           #4                  // String JohnSmith                                                               
      16: astore        5                                                                                                     
      18: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;                               
      21: aload_3                                                                                                             
      22: aload         4                                                                                                     
      24: if_acmpne     31                                                                                                    
      27: iconst_1                                                                                                            
      28: goto          32                                                                                                    
      31: iconst_0                                                                                                            
      32: invokevirtual #6                  // Method java/io/PrintStream.println:(Z)V                                        
      35: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;                               
      38: aload         4                                                                                                     
      40: aload         5                                                                                                     
      42: if_acmpne     49                                                                                                    
      45: iconst_1                                                                                                            
      46: goto          50                                                                                                    
      49: iconst_0                                                                                                            
      50: invokevirtual #6                  // Method java/io/PrintStream.println:(Z)V                                        
      53: return                                                                                                              
}                                                                                                                             
 4: invokedynamic #3,  0              // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;
10: ldc           #4                  // String JohnSmith
14: ldc           #4                  // String JohnSmith