ก่อนอื่นเรากำลังพูดถึงตัวแปรท้องถิ่นเท่านั้น ขั้นสุดท้ายอย่างมีประสิทธิภาพใช้ไม่ได้กับฟิลด์ นี่เป็นสิ่งสำคัญเนื่องจากความหมายสำหรับfinalฟิลด์มีความแตกต่างกันมากและอยู่ภายใต้การปรับแต่งคอมไพเลอร์จำนวนมากและสัญญาโมเดลหน่วยความจำโปรดดู17.5.1 ดอลลาร์ในความหมายของฟิลด์สุดท้าย
ในระดับพื้นผิวfinalและeffectively finalสำหรับตัวแปรท้องถิ่นนั้นเหมือนกัน อย่างไรก็ตาม JLS ทำให้เกิดความแตกต่างอย่างชัดเจนระหว่างทั้งสองซึ่งจริงๆแล้วมีเอฟเฟกต์ที่หลากหลายในสถานการณ์พิเศษเช่นนี้
สถานที่
จากJLS§4.12.4เกี่ยวกับfinalตัวแปร:
ตัวแปรคงเป็นfinalตัวแปรชนิดดั้งเดิมหรือพิมพ์สตริงที่ถูกเตรียมมีการแสดงออกอย่างต่อเนื่อง ( §15.29 ) ไม่ว่าตัวแปรจะเป็นตัวแปรคงที่หรือไม่อาจมีผลกระทบต่อการเริ่มต้นคลาส ( §12.4.1 ), ความเข้ากันได้แบบไบนารี ( §13.1 ), ความสามารถในการเข้าถึง (( 14.22 ) และการกำหนดที่แน่นอน ( §16.1.1 )
ตั้งแต่intดั้งเดิมตัวแปรaเป็นเช่นตัวแปรคงที่
นอกจากนี้จากบทเดียวกันเกี่ยวกับeffectively final:
ตัวแปรบางตัวที่ไม่ได้รับการประกาศขั้นสุดท้ายจะถือว่าเป็นขั้นสุดท้ายอย่างมีประสิทธิผล: ...
ดังนั้นจากวิธีการนี้จะห่วงก็เป็นที่ชัดเจนว่าในตัวอย่างอื่น ๆ ที่aจะไม่ได้รับการพิจารณาเป็นตัวแปรคงที่ตามที่มันเป็นไม่ได้สุดท้ายแต่เพียงสุดท้ายได้อย่างมีประสิทธิภาพ
พฤติกรรม
ตอนนี้เรามีความแตกต่างแล้วให้ค้นหาสิ่งที่เกิดขึ้นและเหตุใดผลลัพธ์จึงแตกต่างกัน
คุณกำลังใช้ตัวดำเนินการเงื่อนไข? :ที่นี่ดังนั้นเราต้องตรวจสอบคำจำกัดความ จากJLS§15.25 :
: มีสามชนิดของการแสดงออกตามเงื่อนไขที่สองและสามสำนวนที่ถูกดำเนินการจะแยกนิพจน์บูลีนแบบมีเงื่อนไข , การแสดงออกที่มีเงื่อนไขที่เป็นตัวเลขและการแสดงออกอ้างอิงเงื่อนไข
ในกรณีนี้เรากำลังพูดถึงนิพจน์เงื่อนไขตัวเลขจากJLS§15.25.2 :
ประเภทของนิพจน์เงื่อนไขตัวเลขถูกกำหนดดังนี้:
และนั่นคือส่วนที่ทั้งสองกรณีได้รับการจัดประเภทแตกต่างกัน
ขั้นสุดท้ายอย่างมีประสิทธิภาพ
เวอร์ชันที่effectively finalตรงตามกฎนี้:
มิฉะนั้นการเลื่อนระดับตัวเลขทั่วไป( §5.6 ) จะถูกนำไปใช้กับตัวถูกดำเนินการที่สองและสามและประเภทของนิพจน์เงื่อนไขคือประเภทที่เลื่อนระดับของตัวถูกดำเนินการที่สองและที่สาม
ซึ่งเป็นลักษณะการทำงานเช่นเดียวกับถ้าคุณจะทำ5 + 'd'เช่นซึ่งผลในการint + char intดูJLS§5.6
การส่งเสริมตัวเลขจะกำหนดประเภทที่เลื่อนระดับของนิพจน์ทั้งหมดในบริบทตัวเลข ประเภทที่เลื่อนขั้นถูกเลือกเพื่อให้แต่ละนิพจน์สามารถแปลงเป็นชนิดที่เลื่อนขั้นได้และในกรณีของการดำเนินการทางคณิตศาสตร์การดำเนินการจะถูกกำหนดสำหรับค่าของชนิดที่เลื่อนขั้น ลำดับของนิพจน์ในบริบทตัวเลขไม่สำคัญสำหรับการเลื่อนระดับตัวเลข กฎมีดังนี้:
[... ]
จากนั้นการขยายการแปลงแบบดั้งเดิมให้กว้างขึ้น ( §5.1.2 ) และการจำกัด การแปลงแบบดั้งเดิม ( §5.1.3 ) จะถูกนำไปใช้กับบางนิพจน์ตามกฎต่อไปนี้:
ในบริบทการเลือกตัวเลขจะใช้กฎต่อไปนี้:
หากการแสดงออกใด ๆ ที่เป็นของชนิดintและเป็นที่ไม่ได้แสดงออกอย่างต่อเนื่อง ( §15.29 ) จากนั้นประเภทการเลื่อนตำแหน่งเป็นintและการแสดงออกอื่น ๆ ที่ไม่ได้เป็นประเภทintได้รับการขยับขยายแปลงดั้งเดิมintไป
ดังนั้นทุกอย่างจะเลื่อนตำแหน่งให้intเป็นaเป็นintแล้ว ที่อธิบายผลลัพธ์ของ97.
สุดท้าย
เวอร์ชันที่มีfinalตัวแปรตรงตามกฎนี้:
หากหนึ่งในตัวถูกดำเนินการคือประเภทTที่Tเป็นbyte, shortหรือcharและถูกดำเนินการอื่น ๆ ที่เป็นการแสดงออกอย่างต่อเนื่อง ( §15.29 ) ประเภทintที่มีค่าซึ่งแสดงในประเภทนั้นประเภทของการแสดงออกที่มีเงื่อนไขคือTT
ตัวแปรสุดท้ายaเป็นประเภทintและนิพจน์คงที่ (เนื่องจากเป็นfinal) มันเป็นแทนได้ดังนั้นผลที่เป็นประเภทchar สรุปว่าการส่งออกchara
ตัวอย่างสตริง
ตัวอย่างที่มีความเท่าเทียมกันของสตริงจะขึ้นอยู่กับความแตกต่างหลักเดียวกันfinalตัวแปรจะถือว่าเป็นนิพจน์ / ตัวแปรคงที่และeffectively finalไม่ใช่
ใน Java สตริงภายในจะขึ้นอยู่กับนิพจน์คงที่ดังนั้น
"a" + "b" + "c" == "abc"
เป็นtrueเช่นกัน (dont ใช้นี้สร้างในรหัสจริง)
ดูJLS§3.10.5 :
ยิ่งไปกว่านั้นสตริงลิเทอรัลมักจะอ้างถึงอินสแตนซ์ของคลาสสตริงเดียวกันเสมอ เนื่องจากสตริงลิเทอรัล - หรือโดยทั่วไปแล้วสตริงที่เป็นค่าของนิพจน์คงที่ ( §15.29 ) - เป็น"ภายใน"เพื่อแชร์อินสแตนซ์ที่ไม่ซ้ำกันโดยใช้เมธอดString.intern( §12.5 )
มองข้ามได้ง่ายเพราะพูดถึงตัวอักษรเป็นหลัก แต่จริงๆแล้วมันก็ใช้กับนิพจน์คงที่เช่นกัน