Pertama-tama, kita hanya berbicara tentang variabel lokal . Final yang efektif tidak berlaku untuk bidang. Ini penting, karena semantik untuk final
bidang sangat berbeda dan tunduk pada pengoptimalan kompiler berat dan janji model memori, lihat $ 17.5.1 tentang semantik bidang akhir.
Di tingkat permukaan final
dan effectively final
untuk variabel lokal memang identik. Namun, JLS membuat perbedaan yang jelas antara keduanya yang sebenarnya memiliki berbagai macam efek dalam situasi khusus seperti ini.
Premis
Dari JLS§4.12.4 tentang final
variabel:
Sebuah variabel konstan adalah final
variabel tipe primitif atau tipe String yang diinisialisasi dengan ekspresi konstan ( §15.29 ). Apakah suatu variabel adalah variabel konstan atau tidak, mungkin memiliki implikasi sehubungan dengan inisialisasi kelas ( §12.4.1 ), kompatibilitas biner ( §13.1 ), keterjangkauan ( §14.22 ), dan penugasan yang pasti ( §16.1.1 ).
Karena int
primitif, variabelnya a
adalah variabel konstan .
Selanjutnya dari bab yang sama tentang effectively final
:
Variabel tertentu yang tidak dinyatakan final malah dianggap final secara efektif: ...
Jadi dari cara ini bernada, jelas bahwa dalam contoh lain, a
yang tidak dianggap sebagai variabel konstan, karena belum final , tetapi hanya efektif akhir.
Tingkah laku
Sekarang kita memiliki perbedaan, mari kita cari apa yang terjadi dan mengapa keluarannya berbeda.
Anda menggunakan operator bersyarat di ? :
sini, jadi kita harus memeriksa definisinya. Dari JLS§15.25 :
Ada tiga jenis ekspresi kondisional, diklasifikasikan menurut ekspresi operan kedua dan ketiga: ekspresi bersyarat boolean , ekspresi bersyarat numerik , dan ekspresi bersyarat referensi .
Dalam hal ini, kita berbicara tentang ekspresi kondisional numerik , dari JLS§15.25.2 :
Jenis ekspresi bersyarat numerik ditentukan sebagai berikut:
Dan itu adalah bagian di mana kedua kasus diklasifikasikan secara berbeda.
efektif akhir
Versi yang effectively final
cocok dengan aturan ini:
Jika tidak, promosi numerik umum ( §5.6 ) diterapkan ke operan kedua dan ketiga, dan jenis ekspresi kondisional adalah jenis yang dipromosikan dari operan kedua dan ketiga.
Yang merupakan perilaku yang sama seperti yang akan Anda lakukan 5 + 'd'
, yaitu int + char
, yang menghasilkan int
. Lihat JLS§5.6
Promosi numerik menentukan jenis yang dipromosikan dari semua ekspresi dalam konteks numerik. Jenis yang dipromosikan dipilih sedemikian rupa sehingga setiap ekspresi dapat dikonversi ke jenis yang dipromosikan, dan, dalam kasus operasi aritmatika, operasi tersebut ditentukan untuk nilai dari jenis yang dipromosikan. Urutan ekspresi dalam konteks numerik tidak signifikan untuk promosi numerik. Aturannya adalah sebagai berikut:
[...]
Selanjutnya, konversi primitif pelebaran ( §5.1.2 ) dan konversi primitif mempersempit ( §5.1.3 ) diterapkan ke beberapa ekspresi, menurut aturan berikut:
Dalam konteks pilihan numerik, aturan berikut berlaku:
Jika ada ekspresi berjenis int
dan bukan merupakan ekspresi konstan ( §15.29 ), maka jenis yang dipromosikan adalah int
, dan ekspresi lain yang bukan berjenis int
menjalani konversi primitif yang melebar menjadi int
.
Jadi semuanya dipromosikan menjadi int
apa a
adanya int
. Itu menjelaskan keluaran dari 97
.
terakhir
Versi dengan final
variabel cocok dengan aturan ini:
Jika salah satu operan bertipe T
where T
is byte
,, short
or char
, dan operand lainnya adalah ekspresi konstan ( §15.29 ) dari tipe int
yang nilainya dapat direpresentasikan dalam tipeT
, maka tipe ekspresi kondisionalnya adalah T
.
Variabel terakhir a
adalah tipe int
dan ekspresi konstan (karena memang demikian final
). Ini dapat direpresentasikan sebagai char
, maka hasilnya adalah tipe char
. Itu menyimpulkan hasilnyaa
.
Contoh string
Contoh persamaan string didasarkan pada perbedaan inti yang sama, final
variabel diperlakukan sebagai ekspresi / variabel konstan, daneffectively final
tidak.
Di Java, string interning didasarkan pada ekspresi konstan
"a" + "b" + "c" == "abc"
adalah true
juga (tidak menggunakan konstruksi ini dalam kode nyata).
Lihat JLS§3.10.5 :
Selain itu, literal string selalu mengacu pada instance kelas String yang sama. Ini karena string literal - atau, lebih umum , string yang merupakan nilai ekspresi konstan ( §15.29 ) - " disimpan " sehingga dapat berbagi instance unik, menggunakan metode String.intern
( §12.5 ).
Mudah untuk dilupakan karena ini terutama berbicara tentang literal, tetapi sebenarnya juga berlaku untuk ekspresi konstan.