Quando dichiari una variabile String(che è immutabile ) come finale la inizializzi con un'espressione costante in fase di compilazione, diventa anche un'espressione costante in fase di compilazione e il suo valore viene sottolineato dal compilatore in cui viene utilizzato. Quindi, nel tuo secondo esempio di codice, dopo aver incorporato i valori, la concatenazione di stringhe viene tradotta dal compilatore in:
String concat = "str" + "ing"; // which then becomes `String concat = "string";`
che se confrontato con "string"ti darà true, perché i valori letterali delle stringhe sono internati .
Da JLS §4.12.4 - finalVariabili :
Una variabile di tipo o tipo primitivo String, che è finale inizializzata con un'espressione costante in fase di compilazione (§15.28), è chiamata variabile costante .
Anche da JLS § 15.28 - Espressione costante:
Costanti in fase di compilazione espressioni del tipo Stringsono sempre "internati" , in modo da condividere le istanze univoche, utilizzando il metodo String#intern().
Questo non è il caso nel tuo primo esempio di codice, dove le Stringvariabili non lo sono final. Quindi, non sono espressioni costanti in fase di compilazione. L'operazione di concatenazione verrà ritardata fino al runtime, portando così alla creazione di un nuovo Stringoggetto. È possibile verificarlo confrontando il codice byte di entrambi i codici.
Il primo esempio di codice (non finalversione) viene compilato nel seguente codice byte:
Code:
0: ldc #2; //String str
2: astore_1
3: ldc #3; //String ing
5: astore_2
6: new #4; //class java/lang/StringBuilder
9: dup
10: invokespecial #5; //Method java/lang/StringBuilder."<init>":()V
13: aload_1
14: invokevirtual #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
17: aload_2
18: invokevirtual #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
21: invokevirtual #7; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
24: astore_3
25: getstatic #8; //Field java/lang/System.out:Ljava/io/PrintStream;
28: aload_3
29: ldc #9; //String string
31: if_acmpne 38
34: iconst_1
35: goto 39
38: iconst_0
39: invokevirtual #10; //Method java/io/PrintStream.println:(Z)V
42: return
Chiaramente sta memorizzando stre ingin due variabili separate, e usando StringBuilderper eseguire l'operazione di concatenazione.
Considerando che il tuo secondo esempio di codice ( finalversione) è simile al seguente:
Code:
0: ldc #2; //String string
2: astore_3
3: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream;
6: aload_3
7: ldc #2; //String string
9: if_acmpne 16
12: iconst_1
13: goto 17
16: iconst_0
17: invokevirtual #4; //Method java/io/PrintStream.println:(Z)V
20: return
Quindi incorpora direttamente la variabile finale per creare String stringal momento della compilazione, che viene caricata ldcdall'operazione nel passaggio 0. Quindi la seconda stringa letterale viene caricata ldcdall'operazione nel passaggio 7. Non comporta la creazione di alcun nuovo Stringoggetto in fase di esecuzione. Le String sono già note al momento della compilazione e vengono internate.