Saat mendeklarasikan properti, metode, dan kelas di Java, final kata kunci dapat digunakan untuk memodifikasinya. Variabel akhir adalah konstan dan hanya dapat ditetapkan sekali; Metode terakhir tidak dapat ditulis ulang oleh subkelas; Kelas terakhir tidak dapat diwariskan.
1. Anggota terakhir
Mendeklarasikan bidang akhir membantu pengoptimal membuat keputusan optimisasi yang lebih baik, karena jika kompiler tahu bahwa nilai bidang tidak akan berubah, itu dapat dengan aman menyimpan nilai dalam register. Bidang terakhir juga memberikan tingkat keamanan tambahan dengan membuat kompiler memaksa bidang menjadi hanya baca.
1.1 Tentang Penugasan Anggota Akhir
1) Di Java, variabel biasa dapat diinisialisasi secara default. Tetapi variabel jenis akhir harus diinisialisasi secara eksplisit.
2) Anggota akhir dapat dan hanya dapat diinisialisasi sekali.
3) Anggota akhir harus diinisialisasi pada deklarasi (menetapkan nilai secara langsung ke variabel akhir ketika didefinisikan) atau dalam konstruktor, dan tidak dapat diinisialisasi di tempat lain.
Contoh 1 Bat.java
BAT kelas publik {final ganda pi = 3.14; // Tetapkan int final i saat didefinisikan; // Karena itu harus diinisialisasi dalam Konstruktor, daftar Final Daftar <Bat> tidak dapat ditetapkan di sini; // Karena itu harus diinisialisasi dalam konstruktor, kelelawar () tidak dapat ditetapkan di sini {i = 100; List = new LinkedList <Bat> (); } Bat (int ii, daftar <bat> l) {i = ii; Daftar = L; } public static void main (string [] args) {bat b = new bat (); B.List.Add (BAT baru ()); // bi = 25; // b.list = ArrayList baru <Bat> (); System.out.println ("i =" + bi + "Jenis daftar:" + b.list.getClass ()); b = kelelawar baru (23, new ArrayList <Bat> ()); B.List.Add (BAT baru ()); System.out.println ("i =" + bi + "Jenis daftar:" + b.list.getClass ()); }}
hasil:
I = 100 Jenis Daftar: kelas java.util.linkedlisti = 23 Jenis daftar: kelas java.util.arraylist
Ada dua baris pernyataan dalam metode utama yang dikomentari. Jika Anda menghapus komentar, program tidak akan dapat dikompilasi. Ini berarti bahwa tidak peduli apakah itu nilai I atau jenis daftar, setelah diinisialisasi, itu tidak dapat diubah. Namun B dapat menentukan nilai I atau jenis daftar dengan menginisialisasi kembali.
1.2 Inisialisasi tidak valid bidang referensi akhir
Agak merepotkan untuk menggunakan bidang akhir dengan benar, terutama untuk referensi objek yang konstruktornya dapat melemparkan pengecualian. Karena bidang akhir harus diinisialisasi hanya sekali di setiap konstruktor, jika konstruktor yang dirujuk oleh objek akhir dapat melempar pengecualian, kompiler dapat melaporkan kesalahan yang mengatakan bahwa bidang tersebut belum diinisialisasi. Kompiler umumnya cukup pintar untuk menemukan bahwa inisialisasi di setiap cabang dua cabang kode mutex (mis., Jika ... lain blok) hanya terjadi sekali, tetapi biasanya tidak begitu "memaafkan" untuk mencoba ... menangkap blok.
Kode berikut biasanya memiliki masalah.
class thingie {public static thingie getDefaultaltie () {return new thingie (); }} kelas publik foo {private final thingie thingie; public foo () {coba {thingie = new thingie (); } catch (exception e) {thingie = thingie.getDefaultethie (); // error: Final Field Thingie mungkin sudah ditetapkan}}}
Anda dapat memodifikasi ini.
kelas publik foo {private final thingie thingie; public foo () {Thingie Tempterhie; Coba {Tempterhie = new thingie (); } catch (exception e) {temphingie = thingie.getDefaultaltie (); } Thingie = Tempterhie; }}
1.3 Tentang Penggunaan Anggota Akhir
Saat Anda mendefinisikan variabel di kelas, tambahkan kata kunci akhir sebelum itu, itu berarti bahwa setelah variabel ini diinisialisasi, itu tidak dapat diubah. Arti kekambalan di sini adalah bahwa nilainya tidak dapat diubah untuk tipe dasar, dan rujukannya tidak dapat diubah lagi untuk variabel objek. Namun, objek itu sendiri dapat dimodifikasi, dan Java tidak menyediakan cara untuk membuat objek apa pun konstan. Keterbatasan ini juga cocok dalam array, yang merupakan objek.
Contoh 2
private final int val_one = 9; private static final int val_two = 99; public static final int val_three = 999;
Karena val_one dan val_tow adalah tipe primitif akhir dengan nilai waktu kompilasi, keduanya dapat digunakan sebagai konstanta waktu kompilasi dan tidak ada perbedaan yang signifikan. Val_Three adalah cara yang lebih khas untuk mendefinisikan konstanta: didefinisikan sebagai publik, dapat digunakan di luar paket; didefinisikan sebagai statis untuk menekankan hanya satu salinan; didefinisikan sebagai final untuk menunjukkan bahwa itu adalah konstan.
Variabel bertanda final menjadi konstan, tetapi "konstan" ini hanya dapat digunakan di dalam kelas ini dan tidak dapat digunakan langsung di luar kelas. Namun, ketika kami menggunakan final statis publik untuk menandai konstan, konstan ini menjadi konstan global (bidang yang statis dan final hanya menempati ruang penyimpanan yang tidak dapat diubah). Selain itu, konstanta yang didefinisikan dengan cara ini hanya dapat diberi nilai yang ditetapkan bila didefinisikan, dan tidak ada tempat lain yang dapat melakukannya.
Contoh 3
nilai kelas {int i; nilai publik (int i) {this.i = i; }} public class finalData {private static random rand = new random (); ID string pribadi; public finalData (string id) {this.id = id; } private final int i4 = rand.nextint (20); static final int i5 = rand.nextint (20); string publik ToString () {return id + ":" + "i4:" + i4 + ", i5 =" + i5; } public static void main (string [] args) {finalData fd1 = finalData baru ("fd1"); System.out.println (FD1); System.out.println ("Membuat FinalData baru"); FinalData fd2 = finalData baru ("fd2"); System.out.println (FD1); System.out.println (FD2); }}
hasil
FD1: I4: 6, i5 = 3creating FinalDataFD1 baru: I4: 6, I5 = 3FD2: I4: 17, I5 = 3
Bagian Contoh menunjukkan perbedaan antara mendefinisikan nilai akhir sebagai statis (I5) dan non-statis (I4). Perbedaan ini hanya akan muncul ketika nilai diinisialisasi selama runtime, karena kompiler memperlakukan nilai yang dikompilasi secara merata. (Dan mereka mungkin menghilang dari optimasi.) Anda akan melihat perbedaan ini ketika Anda menjalankan program. Perhatikan bahwa di FD1 dan FD2, nilai i5 tidak dapat diubah dengan membuat objek finalData kedua. Ini karena statis, yang diinisialisasi saat memuat, tidak setiap kali objek baru dibuat.
Contoh 4
nilai kelas {int i; nilai publik (int i) {this.i = i; }} kelas publik ... {nilai privat v1 = nilai baru (11); nilai akhir pribadi v2 = nilai baru (22); nilai akhir statis privat v3 = nilai baru (33); ...} public static void main (string [] args) {... fd1.v2.i ++; // ok-objek tidak konstan! fd1.v1 = nilai baru (9); // ok-tidak fd1.v2 = nilai baru (0); // kesalahan: tidak dapat mengubah referensi fd1.v3 = nilai baru (1); // kesalahan: tidak dapat mengubah referensi ...} Variabel dari V1 ke V3 menggambarkan arti referensi akhir. Seperti yang dapat Anda lihat di Main (), Anda tidak dapat berpikir bahwa Anda tidak dapat mengubah nilainya hanya karena V2 adalah final. Karena ini adalah referensi, final berarti Anda tidak dapat menunjuk V2 ke objek baru lainnya lagi.
Contoh 5
kelas publik ... {private final int [] a = {1,2,3,4,5,6}; …} Public static void main (string [] args) {... for (int i = 0; i <fd1.a.length; i ++) fd1.a [i] ++; // ok-objek tidak konstan! fd1.a = int baru [3]; // kesalahan: tidak dapat mengubah referensi ...} Memiliki makna yang sama untuk array (dapat mengubah nilainya, tetapi tidak dapat menunjuk ke objek baru), sebuah array adalah referensi lain.
1.4 Selesaikan keterbatasan array akhir
Meskipun referensi array dapat dinyatakan final, unsur -unsur array tidak bisa. Ini berarti bahwa kedua kelas yang memaparkan bidang array akhir publik atau mengembalikan referensi ke bidang -bidang tersebut melalui metode mereka dapat berubah.
// tidak dapat diubah - array negara dapat dimodifikasi oleh // callerpublicclass dangousstates {private final string [] states = new string [] {"alabama", "alaska", "ect"}; string publik [] getStates () {return state; }}
Demikian juga, meskipun referensi objek dapat dinyatakan sebagai bidang akhir, objek yang dirujuknya masih dapat berubah. Jika Anda ingin membuat objek invarian menggunakan bidang akhir, Anda harus mencegah referensi ke array atau objek yang dapat berubah dari "melarikan diri" kelas Anda. Untuk melakukan ini tanpa harus mengkloning array berulang kali, cara mudah adalah mengubah array menjadi daftar.
// Immutable - Mengembalikan daftar yang tidak dapat dikodifikasikan sebagai gantinya PublicClass Safestates {private final string [] states = new string [] {"alabama", "alaska", "ect"}; daftar final private stateSaSlist = new abstractList () {objek publik get (int n) {return state [n]; } public int size () {return state.length; }}; daftar publik getStates () {return statesaslist; }}
1.5 Tentang Penggunaan Parameter Akhir
Penggunaan lain adalah untuk menentukan parameter dalam metode ini sebagai final. Untuk variabel tipe dasar, ini tidak memiliki signifikansi praktis, karena variabel nilai lulus tipe dasar saat memanggil metode, yaitu, Anda dapat mengubah variabel parameter dalam metode tanpa mempengaruhi pernyataan panggilan. Namun, untuk variabel objek, ini sangat praktis karena variabel objek dilewatkan referensi saat lewat. Dengan cara ini, modifikasi variabel objek Anda dalam metode ini juga akan mempengaruhi variabel objek dalam pernyataan panggilan. Ketika Anda tidak perlu mengubah variabel objek sebagai parameter dalam metode ini, secara eksplisit menggunakan Deklarasi Final untuk Deklarasi akan mencegah Anda dari memodifikasi dan mempengaruhi metode panggilan yang tidak disengaja.
1.6 Tentang variabel parameter di kelas dalam
Selain itu, saat menggunakan variabel parameter dalam metode di kelas dalam, variabel parameter ini harus dinyatakan final sebelum dapat digunakan.
Contoh 6 incass.java
kelas publik termasuk {void innerclass (string final str) {class iclass {iClass () {System.out.println (str); }} Iclass ic = iClass baru (); } public static void main (string [] args) {incass inc = new incass (); Inc.InnerClass ("Hello"); }} 2. Metode terakhir
2.1 Penggunaan Metode Akhir
1) Untuk memastikan bahwa perilaku fungsi tertentu tetap tidak berubah selama proses warisan dan tidak dapat diganti, metode terakhir dapat digunakan.
2) Semua metode pribadi dan statis di kelas secara alami final.
2.2 Kata kunci akhir dan pribadi
Semua metode pribadi di kelas secara implisit ditentukan bersifat final. Karena metode pribadi tidak dapat digunakan, itu tidak dapat ditimpa.
"Override" hanya akan muncul jika metode adalah bagian dari antarmuka kelas dasar. Artinya, suatu objek harus dapat diubah ke atas menjadi tipe primitifnya dan memanggil metode yang sama. Jika suatu metode bersifat pribadi, itu bukan bagian dari antarmuka kelas dasar. Itu hanya beberapa kode yang tersembunyi di kelas, tetapi dengan nama yang sama. Namun, jika metode akses publik, terlindungi, atau paket dihasilkan dengan cara yang sama di kelas ekspor, metode ini tidak akan menghasilkan kasus "hanya dengan nama yang sama" yang terjadi di kelas dasar. Pada titik ini, Anda tidak mengganti metode ini, baru saja menghasilkan metode baru. Karena metode pribadi tidak dapat disentuh dan dapat disembunyikan secara efektif, tidak ada lagi yang perlu dipertimbangkan kecuali untuk keberadaan struktur organisasi kelasnya.
3. Kelas terakhir
Ketika kelas didefinisikan sebagai final, kelas tidak dapat diwarisi. Dan karena kelas akhir melarang warisan, semua metode di kelas akhir secara implisit ditentukan sebagai final karena mereka tidak dapat ditimpa.
Final digunakan dalam kelas atau metode untuk mencegah hubungan antara metode yang rusak. Misalnya, misalkan implementasi metode kelas X mengasumsikan bahwa metode m akan bekerja dengan cara tertentu. Menyatakan x atau m sebagai final akan mencegah kelas turunan mendefinisikan kembali M dengan cara ini, menyebabkan x bekerja secara tidak normal. Meskipun mungkin lebih baik untuk mengimplementasikan X tanpa korelasi internal ini, ini tidak selalu memungkinkan, dan menggunakan final dapat mencegah perubahan yang tidak kompatibel di masa depan.
PS: Perbedaan antara final, akhirnya dan finalisasi