Apa metode defaultnya?
Setelah rilis Java 8, metode baru dapat ditambahkan ke antarmuka, namun antarmuka tetap kompatibel dengan kelas implementasinya. Hal ini penting karena perpustakaan yang Anda kembangkan mungkin digunakan secara luas oleh banyak pengembang. Sebelum Java 8, setelah antarmuka dipublikasikan di perpustakaan kelas, jika metode baru ditambahkan ke antarmuka, aplikasi yang mengimplementasikan antarmuka ini akan berisiko mogok saat menggunakan antarmuka versi baru.
Dengan Java 8, apakah tidak ada bahaya seperti itu? Jawabannya adalah tidak.
Menambahkan metode default ke antarmuka mungkin membuat beberapa kelas implementasi tidak tersedia.
Pertama, mari kita lihat detail metode defaultnya.
Di Java 8, metode di antarmuka bisa diimplementasikan (metode statis di Java 8 juga bisa diimplementasikan di antarmuka, tapi itu topik lain). Metode yang diimplementasikan pada antarmuka disebut metode default, yang diidentifikasi dengan kata kunci default sebagai pengubah. Ketika sebuah kelas mengimplementasikan sebuah antarmuka, ia dapat mengimplementasikan metode yang telah diimplementasikan di antarmuka tersebut, namun hal ini tidak diperlukan. Kelas ini akan mewarisi metode default. Inilah sebabnya ketika antarmuka berubah, kelas implementasi tidak perlu diubah.
Bagaimana dengan banyak warisan?
Ketika sebuah kelas mengimplementasikan lebih dari satu (seperti dua) antarmuka, dan antarmuka ini memiliki metode default yang sama, segalanya menjadi sangat rumit. Metode default manakah yang diwarisi oleh kelas? Juga tidak! Dalam hal ini, kelas itu sendiri (baik secara langsung atau kelas yang lebih tinggi dari pohon warisan) harus mengimplementasikan metode default.
Hal yang sama juga berlaku ketika satu antarmuka mengimplementasikan metode default dan antarmuka lain mendeklarasikan metode default sebagai abstrak. Java 8 mencoba menghindari ambiguitas dan menjaga ketelitian. Jika suatu metode dideklarasikan dalam beberapa antarmuka, maka tidak ada implementasi default yang akan diwarisi dan Anda akan mendapatkan kesalahan waktu kompilasi.
Namun, jika Anda telah mengkompilasi kelas Anda, tidak akan ada kesalahan waktu kompilasi. Pada titik ini, Java 8 tidak konsisten. Ada alasannya tersendiri, dan alasannya bermacam-macam. Saya tidak ingin menjelaskannya secara detail atau membahasnya secara mendalam di sini (karena: versinya sudah dirilis, waktu pembahasannya terlalu lama, dan platform ini belum pernah ada). diskusi seperti itu).
1. Misalkan Anda memiliki dua antarmuka dan satu kelas implementasi.
2. Salah satu antarmuka mengimplementasikan metode default m().
3. Kompilasi antarmuka dan kelas implementasi bersama-sama.
4. Ubah antarmuka yang tidak berisi metode m() dan nyatakan metode m() sebagai abstrak.
5. Kompilasi ulang antarmuka yang dimodifikasi secara terpisah.
6. Jalankan kelas implementasi.
1. Ubah antarmuka yang berisi metode abstrak m() dan buat implementasi default.
2. Kompilasi antarmuka yang dimodifikasi
3. Jalankan kelas: Gagal.
Ketika dua antarmuka menyediakan implementasi default untuk metode yang sama, metode ini tidak dapat dipanggil kecuali kelas implementasi juga mengimplementasikan metode default (baik secara langsung atau oleh kelas dengan level yang lebih tinggi di pohon warisan).
Contoh kode:
Untuk mendemonstrasikan contoh di atas, saya membuat direktori pengujian untuk C.java, dan ada 3 subdirektori di bawahnya untuk menyimpan I1.java dan I2.java. Direktori pengujian berisi kode sumber C.java kelas C. Direktori dasar berisi versi antarmuka yang dapat dikompilasi dan dijalankan. I1 berisi metode m() dengan implementasi default, dan I2 tidak berisi metode apa pun.
Kelas implementasi berisi metode utama sehingga kita dapat mengeksekusinya dalam pengujian kita. Ini akan memeriksa apakah ada parameter baris perintah, sehingga kita dapat dengan mudah melakukan tes dengan memanggil m() dan tidak memanggil m().
Copy kode kodenya sebagai berikut:
~/github/test$ cat C.java
kelas publik C mengimplementasikan I1, I2 {
public static void main(String[] args) {
C c = baru C();
if(args.panjang == 0){
cm();
}
}
}
~/github/test$ basis kucing/I1.java
antarmuka publik I1 {
kekosongan bawaan m(){
System.out.println("halo antarmuka 1");
}
}
~/github/test$ basis kucing/I2.java
antarmuka publik I2 {
}
Gunakan baris perintah berikut untuk mengkompilasi dan menjalankan:
Salin kode sebagai berikut:~/github/test$ javac -cp .:base C.java
~/github/test$java -cp.:base C
halo antarmuka 1
Direktori yang kompatibel berisi antarmuka I2 dengan metode abstrak m(), dan antarmuka I1 yang tidak dimodifikasi.
Salin kode sebagai berikut:~/github/test$cat kompatibel/I2.java
antarmuka publik I2 {
batal m();
}
Ini tidak dapat digunakan untuk mengkompilasi kelas C:
Salin kode sebagai berikut:~/github/test$ javac -cp .:kompatibel C.java
C.java:1: error: C tidak abstrak dan tidak menimpa metode abstrak m() di I2
kelas publik C mengimplementasikan I1, I2 {
^
1 kesalahan
Pesan kesalahannya sangat tepat. Karena kita memiliki kelas C. yang diperoleh pada kompilasi sebelumnya, jika kita mengkompilasi antarmuka di direktori yang kompatibel, kita masih akan mendapatkan dua antarmuka yang dapat menjalankan kelas implementasi:
Copy kode kodenya sebagai berikut:
~/github/test$ kompatibel dengan javac/I*.java
~/github/test$ java -cp .:kompatibel C
halo antarmuka 1
Direktori ketiga yang disebut salah berisi antarmuka I2 yang juga mendefinisikan metode m():
Copy kode kodenya sebagai berikut:
~/github/test$ kucing salah/I2.java
antarmuka publik I2 {
kekosongan bawaan m(){
System.out.println("halo antarmuka 2");
}
}
Kita harus bersusah payah mengkompilasinya. Meskipun metode m() didefinisikan dua kali, kelas implementasi masih dapat berjalan selama tidak memanggil metode yang ditentukan beberapa kali. Namun, selama kita memanggil metode m(), metode tersebut akan langsung gagal. Berikut adalah parameter baris perintah yang kami gunakan:
Copy kode kodenya sebagai berikut:
~/github/test$ javac salah/*.java
~/github/test$ java -cp .:salah C
Pengecualian di thread "utama" java.lang.IncompatibelClassChangeError: Bertentangan
metode default: I1.m I2.m
di Cm(C.java)
di C.main(C.java:5)
~/github/test$ java -cp .:salah C x
~/github/tes$
sebagai kesimpulan
Saat Anda mem-porting perpustakaan kelas yang menambahkan implementasi default ke antarmuka ke lingkungan Java 8, secara umum tidak akan ada masalah. Setidaknya itulah yang dipikirkan pengembang perpustakaan kelas Java8 ketika mereka menambahkan metode default ke kelas koleksi. Aplikasi yang menggunakan perpustakaan Anda masih mengandalkan perpustakaan Java 7 yang tidak memiliki metode default. Saat menggunakan dan memodifikasi beberapa perpustakaan kelas yang berbeda, kecil kemungkinan terjadinya konflik. Bagaimana hal ini dapat dihindari?
Rancang perpustakaan kelas Anda seperti sebelumnya. Jangan anggap enteng jika mengandalkan cara default. Jangan gunakan sebagai pilihan terakhir. Pilih nama metode dengan bijak untuk menghindari konflik dengan antarmuka lain. Kita akan mempelajari cara menggunakan fitur ini untuk pengembangan dalam pemrograman Java.