เมื่อคุณประกาศตัวแปร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 รู้จักกันแล้วในเวลารวบรวมและพวกเขาจะฝึกงาน