ก่อนอื่นเรากำลังพูดถึงตัวแปรท้องถิ่นเท่านั้น ขั้นสุดท้ายอย่างมีประสิทธิภาพใช้ไม่ได้กับฟิลด์ นี่เป็นสิ่งสำคัญเนื่องจากความหมายสำหรับ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
ที่มีค่าซึ่งแสดงในประเภทนั้นประเภทของการแสดงออกที่มีเงื่อนไขคือT
T
ตัวแปรสุดท้ายa
เป็นประเภทint
และนิพจน์คงที่ (เนื่องจากเป็นfinal
) มันเป็นแทนได้ดังนั้นผลที่เป็นประเภทchar
สรุปว่าการส่งออกchar
a
ตัวอย่างสตริง
ตัวอย่างที่มีความเท่าเทียมกันของสตริงจะขึ้นอยู่กับความแตกต่างหลักเดียวกันfinal
ตัวแปรจะถือว่าเป็นนิพจน์ / ตัวแปรคงที่และeffectively final
ไม่ใช่
ใน Java สตริงภายในจะขึ้นอยู่กับนิพจน์คงที่ดังนั้น
"a" + "b" + "c" == "abc"
เป็นtrue
เช่นกัน (dont ใช้นี้สร้างในรหัสจริง)
ดูJLS§3.10.5 :
ยิ่งไปกว่านั้นสตริงลิเทอรัลมักจะอ้างถึงอินสแตนซ์ของคลาสสตริงเดียวกันเสมอ เนื่องจากสตริงลิเทอรัล - หรือโดยทั่วไปแล้วสตริงที่เป็นค่าของนิพจน์คงที่ ( §15.29 ) - เป็น"ภายใน"เพื่อแชร์อินสแตนซ์ที่ไม่ซ้ำกันโดยใช้เมธอดString.intern
( §12.5 )
มองข้ามได้ง่ายเพราะพูดถึงตัวอักษรเป็นหลัก แต่จริงๆแล้วมันก็ใช้กับนิพจน์คงที่เช่นกัน