Kelas terakhir
Ketika suatu kelas didefinisikan sebagai kelas akhir, itu berarti bahwa kelas tidak dapat diwarisi oleh kelas lain, yaitu, itu tidak dapat digunakan setelah diperluas. Kalau tidak, Anda akan mendapatkan kesalahan selama kompilasi.
paket com.iderzheng.finalkeyword; Public Final Class FinalClass {} // Kesalahan: Tidak dapat mewarisi dari FinalClass PackageClass Extends FinalClass {} Java mendukung mendefinisikan kelas sebagai final, yang tampaknya melanggar prinsip-prinsip dasar pemrograman yang berorientasi objek. Namun, di sisi lain, kelas tertutup juga memastikan bahwa semua metode kelas telah diperbaiki dan tidak akan ada subkelas override untuk dimuat secara dinamis. Ini memberikan lebih banyak kemungkinan bagi kompiler untuk dioptimalkan. Contoh terbaik adalah string, yang merupakan kelas terakhir. Kompiler Java dapat secara langsung mengubah konstanta string (yang terkandung dalam kutipan ganda) menjadi objek string, dan pada saat yang sama secara langsung mengoptimalkan operasi operator + ke dalam konstanta baru, karena modifikasi akhir memastikan bahwa tidak ada subkelas yang mengembalikan nilai yang berbeda untuk operasi penyambungan.
Untuk semua definisi kelas yang berbeda - kelas tingkat atas (global atau paket terlihat), kelas bersarang (kelas internal atau statis bersarang) dapat dimodifikasi dengan final. Namun, secara umum, final sebagian besar digunakan untuk memodifikasi kelas yang didefinisikan sebagai publik, karena untuk kelas non-global, pengubah akses telah membatasi visibilitas mereka, dan sudah sulit untuk mewarisi kelas-kelas ini, sehingga tidak perlu menambahkan lapisan pembatasan akhir.
Juga disebutkan bahwa meskipun kelas anonim tidak dapat diwarisi, mereka tidak terbatas pada final oleh kompiler.
impor java.lang.reflect.modifier; kelas publik {public static void main (string [] args) {runnable anonymous = new runnable () {@Override public void run () {}}; System.out.println (Modifier.isfinal (Anonymous.getClass (). GetModifiers ())); }}Keluaran:
PALSU
Metode terakhir
Terkait erat dengan konsep warisan adalah polimorfisme, yang melibatkan perbedaan antara konsep -konsep utama dan persembunyian (untuk kenyamanan, berikut ini secara kolektif disebut "penulisan ulang"). Namun, tidak seperti definisi metode dalam C ++ apakah kata kunci virtual ditambahkan ke subclass, apakah metode tanda tangan subkelas ditimpa atau disembunyikan, dalam java, subkelas menggunakan tanda tangan metode yang sama untuk menimpa metode kelas induk, yang akan membentuk metode kelas tersembunyi (metode statis), sementara metode objek (metode non-statis) hanya over-writ. Karena Java memungkinkan akses langsung ke metode kelas melalui objek, Java tidak mengizinkan metode kelas dan metode objek memiliki tanda tangan yang sama di kelas yang sama.
Kelas terakhir mendefinisikan bahwa seluruh kelas tidak dapat diwarisi, dan itu juga berarti bahwa semua metode di kelas tidak dapat ditutup dan disembunyikan oleh subkelas. Ketika kelas tidak dimodifikasi dengan final, beberapa metode masih dapat dimodifikasi menggunakan final untuk mencegah metode ini ditulis ulang oleh subkelas.
Demikian pula, desain semacam itu menghancurkan polimorfisme yang berorientasi objek, tetapi metode terakhir dapat memastikan determinisme pelaksanaannya, sehingga memastikan stabilitas panggilan metode. Dalam beberapa desain kerangka kerja, beberapa metode yang diimplementasikan dari kelas abstrak sering terlihat terbatas pada final, karena beberapa kode driver dalam kerangka kerja akan bergantung pada metode ini untuk mencapai tujuan yang ditetapkan, sehingga tidak ada subclass yang menutupinya.
Contoh berikut menunjukkan peran modifikasi akhir dalam berbagai jenis metode:
paket com.iderzheng.other; Kelas Publik FinalMethods {public static void publicstaticMethod () {} public final void publicFinalMethod () {} public static final void publicstaticFinalMethod () {} final void final final {} {} void static final void final final finalfinalfinalfinal finalMethod () {} dilindungi static void void void final finalFinalFinalFinalStaticStaticTatic void staticFinalMethod () {} private static final void privatesTaticFinalMethod () {} private final void privateFinalMethod () {}} paket com.iderzheng.finalkeyword; impor com.iderzheng.other.finalmethods; Metode kelas publik memperluas finalMethods {public static void publicstaticmethod () {} // error: tidak dapat mengganti public final publicFinalMethod () {} // error: tidak dapat mengesampingkan public publictatic publictatic public public public public {{{{{{{{public {public {public {public {public {public {public {public {) void publicstaticFinalMethod () {} // error: tidak dapat mengesampingkan final void final protectedFinalMethod () {} // error: tidak dapat mengesampingkan final static void final static statictaticFinalMethod () {} final finalMethod () {} static static staticfinal staticfinal () {{} static staticfinal staticfinal () {{} static staticfinal staticfinal () {{static static staticfinal () {{static static staticfinal () {} private final void privateFinalMethod () {}} Pertama -tama, perhatikan bahwa dalam contoh di atas, metode final dan metode didefinisikan di bawah paket yang berbeda. Untuk PublicStaticMethod pertama, subclass berhasil menulis ulang metode statis dari kelas induk, tetapi karena itu adalah metode statis, apa yang terjadi sebenarnya adalah "tersembunyi". Secara khusus, metode panggilan.publicstaticmethod () akan menjalankan implementasi di kelas Metode. Saat memanggil finalMethods.publicstaticmethod (), implementasi tidak akan terjadi dengan pemuatan polimorfik dari subkelas, tetapi akan secara langsung menggunakan implementasi finalMethods. Oleh karena itu, saat menggunakan subkelas untuk mengakses metode, visibilitas metode yang ditandatangani oleh kelas induk disembunyikan.
Untuk metode global PublicFinalMethod, seperti yang dijelaskan dalam metode modifikasi akhir, subclass dilarang untuk menimpanya, dan pengecualian akan dilemparkan pada waktu kompilasi. Namun, nama metode sama di subkelas, tetapi memiliki parameter, seperti: publicFinalMethod (String X) OK, karena ini adalah tanda tangan metode sinkron.
Di IntelliJ, IDE menunjukkan peringatan kepada Metode PublicStaticFinalMethod: 'Static' dinyatakan 'final'. Tampaknya berlebihan untuk itu, tetapi dari contoh, dapat dilihat bahwa final juga melarang definisi subkelas dari metode statis untuk menyembunyikannya. Dalam pengembangan aktual, perilaku mendefinisikan metode statis subkelas yang sama dan kelas orang tua sangat diinginkan, karena metode tersembunyi mengharuskan pengembang untuk memperhatikan penggunaan nama kelas yang berbeda untuk mendefinisikan efek yang berbeda, yang mudah menyebabkan kesalahan. Selain itu, di dalam kelas, Anda dapat memanggil metode statis secara langsung tanpa menggunakan nama kelas. Ketika pengembang mewarisi lagi, ia mungkin tidak melihat keberadaan tersembunyi. Secara default, saat menggunakan metode kelas induk, ia akan menemukan bahwa itu bukan hasil yang diharapkan. Oleh karena itu, metode statis harus final secara default dan tidak boleh disembunyikan, jadi IDE berpikir itu adalah modifikasi yang tidak perlu.
Modifikasi yang dilindungi dan metode modifikasi publik di kelas induk terlihat oleh subkelas, sehingga situasi modifikasi akhir metode yang dilindungi adalah sama dengan metode publik. Harus disebutkan bahwa dalam pengembangan aktual, metode statis yang dilindungi umumnya jarang didefinisikan karena metode seperti itu terlalu praktis.
Untuk metode paket kelas induk, subclass di bawah paket yang berbeda tidak terlihat. Metode pribadi telah disesuaikan dan hanya kelas induk yang dapat mengaksesnya. Jadi kompiler memungkinkan subclass untuk menentukan metode yang sama. Tetapi ini tidak membentuk override atau hide, karena kelas induk telah menyembunyikan metode ini melalui pengubah, bukan disebabkan oleh penulisan ulang subkelas. Tentu saja, jika subkelas dan kelas induk berada dalam paket yang sama, maka situasinya akan sama dengan publik sebelumnya dan dilindungi.
Mengapa metode terakhir efisien?
Metode terakhir akan menggunakan mekanisme tertanam untuk mengoptimalkan inline selama kompilasi. Optimasi inline mengacu pada: Penggantian kode fungsi panggilan langsung selama kompilasi, daripada fungsi panggilan saat runtime. Inline perlu mengetahui fungsi mana yang akan digunakan pada akhirnya saat menyusun. Jelas, tidak mungkin menggunakannya tanpa final. Metode non-final dapat ditulis ulang di subkelas. Karena kemungkinan polimorfisme, kompiler tidak dapat menentukan jenis objek yang sebenarnya untuk memanggil metode di masa depan selama tahap kompilasi, dan tidak dapat menentukan metode mana yang akan dihubungi.
Variabel akhir
Sederhananya, variabel akhir dalam Java hanya dapat dan harus diinisialisasi sekali, dan kemudian variabel terikat ke nilainya. Namun, penugasan ini tidak perlu diinisialisasi segera ketika variabel didefinisikan. Java juga mendukung hasil yang berbeda untuk variabel akhir melalui pernyataan bersyarat, tetapi variabel hanya dapat ditetapkan sekali dalam kasus apa pun.
Namun, variabel akhir Java bukan konstanta absolut, karena variabel objek Java hanyalah nilai referensi, jadi final hanya berarti bahwa referensi tidak dapat diubah, dan konten objek masih dapat dimodifikasi. Dibandingkan dengan pointer C/C ++, ini lebih seperti tipe * variabel const daripada variabel tipe const *.
Variabel Java dapat dibagi menjadi dua kategori: variabel lokal (variabel lokal) dan variabel anggota kelas (bidang kelas). Berikut ini adalah kode untuk memperkenalkan situasi inisialisasi mereka secara terpisah.
Variabel lokal
Variabel lokal terutama merujuk ke variabel yang ditentukan dalam metode. Mereka akan menghilang dan menjadi tidak dapat diakses setelah metode. Ada kasus khusus yang dapat dibagi menjadi: parameter fungsi. Untuk kasus ini, inisiasinya terikat pada parameter yang dilewati ketika fungsi dipanggil.
Untuk variabel lokal lainnya, mereka didefinisikan dalam metode ini, dan nilainya dapat diinisialisasi secara kondisional:
Metode String Publik (final Boolean FinalParam) {// Kesalahan: Final Parameter FinalParam mungkin tidak ditetapkan // finalParam = true; Objek akhir finalocal = finalparam? objek baru (): null; final int finalvar; if (finallocal! = null) {finalvar = 21; } else {finalvar = 7; } // Kesalahan: Variabel finalVar mungkin sudah ditetapkan // finalvar = 80; final string terakhir; switch (finalvar) {case 21: finalRet = "me"; merusak; Kasus 7: finalRet = "dia"; merusak; Default: finalRet = null; } return finalRet;} Dari contoh di atas, dapat dilihat bahwa parameter fungsi yang dimodifikasi oleh final tidak dapat diberi nilai baru, tetapi variabel lokal akhir lainnya dapat diberi nilai dalam pernyataan bersyarat. Ini juga memberikan fleksibilitas tertentu untuk final.
Tentu saja, semua kondisi dalam pernyataan bersyarat harus berisi penugasan untuk variabel lokal akhir, jika tidak, Anda akan mendapatkan kesalahan bahwa variabel tersebut mungkin tidak diinisialisasi.
Metode String Publik (Final Objek FinalParam) {final int finalVar; if (finalparam! = null) {finalvar = 21; } final string finalRET; // ERROR: Variabel finalVar mungkin belum diinisialisasi sakelar (finalvar) {case 21: finalRet = "me"; merusak; Kasus 7: finalRet = "dia"; merusak; } // Kesalahan: Final Variabel mungkin belum diinisialisasi pengembalian finalRet;} Secara teori, variabel lokal tidak perlu didefinisikan sebagai final, dan metode desain yang masuk akal harus dapat mempertahankan variabel lokal dengan baik. Hanya saja ketika menggunakan fungsi anonim untuk membuat penutupan dalam metode Java, Java mensyaratkan bahwa variabel lokal yang direferensikan harus didefinisikan sebagai final:
Metode Runnable Publik (String String) {int integer = 12; return new runnable () {@Override public void run () {// error: perlu dinyatakan final system.out.println (string); // Kesalahan: perlu dinyatakan final system.out.println (integer); }};}Bidang kelas
Variabel anggota kelas sebenarnya dapat dibagi menjadi dua jenis: statis dan non-statis. Untuk variabel anggota kelas statis, karena mereka terkait dengan kelas, selain diinisialisasi secara langsung pada waktu definisi, mereka juga dapat ditempatkan di blok statis, dan menggunakan yang terakhir dapat menjalankan pernyataan yang lebih kompleks:
paket com.iderzheng.finalkeyword; impor java.util.hashset; import java.util.linkedhashset; impor java.util.set; kelas publik staticFinalFields {static final int static_final_init_inline = 7; set akhir statis <Integer> static_final_init_static_block; / ** blok statis **/ static {if (system.currentTimeMillis () % 2 == 0) {static_final_init_static_block = hashset baru <> (); } else {static_final_init_static_block = new LinkedHashset <> (); } Static_final_init_static_block.add (7); Static_final_init_static_block.add (21); }}Ada juga blok non-statis di Java yang dapat menginisialisasi variabel anggota non-statis, tetapi untuk variabel-variabel ini, mereka sering ditempatkan dalam konstruktor untuk inisialisasi. Tentu saja, perlu untuk memastikan bahwa setiap variabel akhir diinisialisasi sekali dalam konstruktor. Jika konstruktor lain dipanggil melalui ini (), variabel akhir ini tidak dapat lagi ditetapkan dalam konstruktor.
paket com.iderzheng.finalkeyword; Final Class Public {final long final_init_inline = system.currentTimeMillis (); final final_init_block terakhir; final final_init_constructor final; / ** blok awal **/ {final_init_block = system.nanoTime (); } FinalFields () {this (217); } FinalFields (boolean bool) {final_init_constructor = 721; } FinalFields (long init) {final_init_constructor = init; }}Ketika final digunakan untuk memodifikasi kelas (kelas) dan metode (metode), itu terutama mempengaruhi warisan yang berorientasi objek. Tanpa warisan, tidak akan ada ketergantungan pada kode subkelas pada kelas induk. Oleh karena itu, ketika memodifikasi kode selama pemeliharaan, tidak perlu mempertimbangkan apakah implementasi subkelas akan dihancurkan, yang membuatnya lebih nyaman. Ketika digunakan pada variabel, Java memastikan bahwa nilai variabel tidak akan dimodifikasi. Jika desain lebih lanjut memastikan bahwa anggota kelas tidak dapat dimodifikasi, maka seluruh variabel dapat diubah menjadi konstan, yang sangat bermanfaat untuk pemrograman multi-threaded. Oleh karena itu, final memiliki efek yang sangat baik pada pemeliharaan kode.