เมื่อคุณประกาศตัวแปรString(ซึ่งไม่เปลี่ยนรูป ) เป็นfinalและกำหนดค่าเริ่มต้นด้วยนิพจน์ค่าคงที่แบบคอมไพล์เวลามันจะกลายเป็นนิพจน์ค่าคงที่แบบคอมไพล์เวลาและค่าของมันจะถูกคอมไพล์โดยที่มันถูกใช้ ดังนั้นในตัวอย่างโค้ดที่สองของคุณหลังจากการฝังค่าการต่อสตริงจะถูกแปลโดยคอมไพเลอร์เป็น:
String concat = "str" + "ing"; // which then becomes `String concat = "string";`
ซึ่งเมื่อเทียบกับการ"string"ที่จะทำให้คุณtrueเพราะตัวอักษรของสตริงจะฝึกงาน
จากJLS §4.12.4 - finalตัวแปร :
ตัวแปรชนิดดั้งเดิมหรือประเภทStringที่มีfinalและเริ่มต้นได้ด้วยการแสดงออกที่รวบรวมเวลาคงที่ (§15.28) เรียกว่าตัวแปรคงที่
นอกจากนี้จากJLS §15.28 - การแสดงออกอย่างต่อเนื่อง:
เวลารวบรวมการแสดงออกอย่างต่อเนื่องของชนิดStringมักจะ"ฝึกงาน"String#intern()เพื่อร่วมกันกรณีที่ไม่ซ้ำกันโดยใช้วิธีการ
กรณีนี้ไม่ได้ในตัวอย่างรหัสแรกของคุณที่ตัวแปรไม่ได้String finalดังนั้นจึงไม่ใช่นิพจน์คงที่เวลาคอมไพล์ การดำเนินการเรียงต่อกันจะมีความล่าช้าจนถึงรันไทม์จึงนำไปสู่การสร้างStringวัตถุใหม่ คุณสามารถตรวจสอบได้โดยการเปรียบเทียบรหัสไบต์ของรหัสทั้งสอง
ตัวอย่างรหัสแรก(ไม่ใช่finalรุ่น)จะรวบรวมเป็นรหัสไบต์ต่อไปนี้:
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
เห็นได้ชัดว่ามันมีการจัดเก็บstrและingในสองตัวแปรที่แยกจากกันและใช้StringBuilderในการดำเนินการเชื่อมต่อ
ในขณะที่ตัวอย่างโค้ดที่สองของคุณ( finalเวอร์ชัน)มีลักษณะดังนี้:
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
ดังนั้นจึงโดยตรง inlines ตัวแปรสุดท้ายที่จะสร้าง String stringที่รวบรวมเวลาซึ่งเป็นที่โหลดโดยการดำเนินการในขั้นตอนที่ldc 0แล้วตัวอักษรสตริงที่สองคือการโหลดโดยการดำเนินการในขั้นตอนที่ldc 7ไม่เกี่ยวข้องกับการสร้างStringวัตถุใหม่ที่รันไทม์ String รู้จักกันแล้วในเวลารวบรวมและพวกเขาจะฝึกงาน