JavaRush /Blog Java /Random-MS /Kaedah Lalai dalam Java 8: Apa yang Boleh dan Tidak Boleh...
Spitfire
Tahap

Kaedah Lalai dalam Java 8: Apa yang Boleh dan Tidak Boleh Buat?

Diterbitkan dalam kumpulan
Terjemahan artikel yang ditulis oleh Peter Verhas bertarikh April 2014. Kaedah Lalai dalam Java 8: Apa yang Boleh dan Tidak Boleh Buat?  - 1Daripada penterjemah: istilah " kaedah lalai " baru sahaja muncul di Jawa dan saya tidak pasti sama ada terdapat terjemahan yang mantap ke dalam bahasa Rusia untuknya. Saya akan menggunakan istilah "kaedah lalai", walaupun saya rasa ia tidak sesuai. Saya menjemput anda untuk membincangkan terjemahan yang lebih berjaya.

Apakah kaedah lalai

Kini, dengan keluaran Java 8, anda boleh menambah kaedah baharu pada antara muka supaya antara muka kekal serasi dengan kelas yang melaksanakannya. Ini sangat penting jika anda membangunkan perpustakaan yang digunakan oleh ramai pengaturcara dari Kyiv ke New York. Sebelum Java 8, jika anda menentukan antara muka dalam perpustakaan, anda tidak boleh menambah kaedah padanya tanpa mengambil risiko bahawa sesetengah aplikasi yang menjalankan antara muka anda akan rosak apabila ia dikemas kini. Jadi, di Java 8 anda tidak boleh takut lagi dengan ini? Tidak, awak tak boleh. Menambah kaedah lalai pada antara muka boleh menyebabkan sesetengah kelas tidak boleh digunakan. Mari kita lihat perkara yang baik tentang kaedah lalai. Dalam Java 8, kaedah ini boleh dilaksanakan secara langsung dalam antara muka. (Kaedah statik dalam antara muka kini boleh juga dilaksanakan, tetapi itu cerita lain.) Kaedah yang dilaksanakan dalam antara muka dipanggil kaedah lalai dan dilambangkan dengan kata kunci lalai . Jika kelas melaksanakan antara muka, ia boleh, tetapi tidak perlu, melaksanakan kaedah yang dilaksanakan dalam antara muka. Kelas mewarisi pelaksanaan lalai. Inilah sebabnya mengapa tidak perlu mengubah suai kelas apabila menukar antara muka yang mereka laksanakan.

Pusaka berbilang?

Perkara menjadi lebih rumit jika kelas melaksanakan lebih daripada satu (katakan, dua) antara muka, dan mereka melaksanakan kaedah lalai yang sama. Kaedah manakah yang akan diwarisi oleh kelas? Jawapannya tiada. Dalam kes ini, kelas mesti melaksanakan kaedah itu sendiri (sama ada secara langsung atau dengan mewarisinya daripada kelas lain). Keadaannya sama jika hanya satu antara muka mempunyai kaedah lalai, dan dalam satu lagi kaedah yang sama adalah abstrak. Java 8 cuba untuk berdisiplin dan mengelakkan situasi yang tidak jelas. Jika kaedah diisytiharkan dalam lebih daripada satu antara muka, maka tiada pelaksanaan lalai diwarisi oleh kelas - anda akan mendapat ralat kompilasi. Walaupun, anda mungkin tidak mendapat ralat kompilasi jika kelas anda sudah disusun. Java 8 tidak cukup mantap dalam hal ini. Terdapat sebab untuk ini, yang saya tidak mahu membincangkannya (contohnya: keluaran Java telah dikeluarkan dan masa untuk perbincangan telah lama berlalu dan secara amnya, ini bukan tempat untuk mereka).
  • Katakan anda mempunyai dua antara muka dan satu kelas melaksanakan kedua-duanya.
  • Salah satu antara muka melaksanakan kaedah lalai m().
  • Anda menyusun semua antara muka dan kelas.
  • Anda menukar antara muka yang tidak mempunyai kaedah m() dengan mengisytiharkannya sebagai kaedah abstrak.
  • Anda hanya menyusun antara muka yang diubah suai.
  • Mulakan kelas.
Kaedah Lalai dalam Java 8: Apa yang Boleh dan Tidak Boleh Buat?  - 2Dalam kes ini kelas berfungsi. Anda tidak boleh menyusunnya dengan antara muka yang dikemas kini, tetapi ia telah disusun dengan versi yang lebih lama dan oleh itu berfungsi. Sekarang
  • tukar antara muka dengan kaedah abstrak m() dan tambahkan pelaksanaan lalai.
  • Susun antara muka yang diubah suai.
  • Jalankan kelas: ralat.
Apabila terdapat dua antara muka yang menyediakan pelaksanaan lalai kaedah, kaedah itu tidak boleh dipanggil dalam kelas melainkan ia dilaksanakan oleh kelas itu sendiri (sekali lagi, sama ada sendiri atau diwarisi daripada kelas lain). Kaedah Lalai dalam Java 8: Apa yang Boleh dan Tidak Boleh Buat?  - 3Serasi kelas. Ia boleh dimuatkan dengan antara muka yang diubah suai. Ia mungkin berjalan sehingga kaedah dipanggil yang mempunyai pelaksanaan lalai dalam kedua-dua antara muka.

Contoh kod

Kaedah Lalai dalam Java 8: Apa yang Boleh dan Tidak Boleh Buat?  - 4Untuk menunjukkan perkara di atas, saya mencipta direktori ujian untuk kelas C.java dan 3 subdirektori untuk antara muka dalam fail I1.java dan I2.java. Direktori akar untuk ujian mengandungi kod sumber untuk kelas C.java. Direktori asas mengandungi versi antara muka yang sesuai untuk pelaksanaan dan penyusunan: antara muka I1 mempunyai kaedah lalai m(); Antara muka I2 belum mempunyai sebarang kaedah. Kelas mempunyai kaedah mainsupaya kita boleh melaksanakannya untuk mengujinya. Ia menyemak sama ada terdapat sebarang hujah baris perintah, jadi kami boleh melaksanakannya dengan mudah sama ada dengan atau tanpa memanggil m().
~/github/test$ cat C.java
public class C implements I1, I2 {
  public static void main(String[] args) {
    C c = new C();
    if( args.length == 0 ){
      c.m();
    }
  }
}
~/github/test$ cat base/I1.java
public interface I1 {
  default void m(){
    System.out.println("hello interface 1");
  }
}
~/github/test$ cat base/I2.java
public interface I2 {
}
Anda boleh menyusun dan menjalankan kelas dari baris arahan.
~/github/test$ javac -cp .:base C.java
~/github/test$ java -cp .:base C
hello interface 1
Direktori yang serasi mengandungi versi antara muka I2 yang mengisytiharkan kaedah m() sebagai abstrak, dan juga, atas sebab teknikal, salinan I1.java yang tidak diubah suai.
~/github/test$ cat compatible/I2.java

public interface I2 {
  void m();
}
Set sedemikian tidak boleh digunakan untuk menyusun kelas C:
~/github/test$ javac -cp .:compatible C.java
C.java:1: error: C is not abstract and does not override abstract method m() in I2
public class C implements I1, I2 {
       ^
1 error
Mesej ralat adalah sangat tepat. Walau bagaimanapun, kami mempunyai C.class daripada kompilasi sebelumnya dan, jika kami menyusun antara muka ke dalam direktori yang serasi, kami akan mempunyai dua antara muka yang masih boleh digunakan untuk menjalankan kelas:
~/github/test$ javac compatible/I*.java
~/github/test$ java -cp .:compatible C
hello interface 1
Direktori ketiga - wrong- mengandungi versi I2, yang juga mengisytiharkan kaedah m():
~/github/test$ cat wrong/I2.java
public interface I2 {
  default void m(){
    System.out.println("hello interface 2");
  }
}
Anda tidak perlu risau tentang kompilasi. Walaupun kaedah diisytiharkan dua kali, kelas masih boleh digunakan dan dijalankan sehingga kaedah m() dipanggil. Inilah yang kita perlukan hujah baris arahan untuk:
~/github/test$ javac wrong/*.java
~/github/test$ java -cp .:wrong C
Exception in thread "main" java.lang.IncompatibleClassChangeError: Conflicting default methods: I1.m I2.m
    at C.m(C.java)
    at C.main(C.java:5)
~/github/test$ java -cp .:wrong C x
~/github/test$

Kesimpulan

Apabila anda mengalihkan perpustakaan anda ke Java 8 dan menukar antara muka anda untuk memasukkan kaedah lalai, anda mungkin tidak akan menghadapi sebarang masalah. Sekurang-kurangnya, itulah yang diharapkan oleh pembangun perpustakaan Java 8 kerana mereka menambah fungsi. Aplikasi yang menggunakan pustaka anda masih menggunakannya untuk Java 7, di mana tiada kaedah lalai. Jika beberapa perpustakaan digunakan bersama, terdapat kemungkinan konflik. Bagaimana untuk mengelakkannya? Reka bentuk API perpustakaan anda dengan cara yang sama seperti sebelum ini. Jangan leka dengan bergantung pada keupayaan kaedah lalai. Mereka adalah pilihan terakhir. Pilih nama dengan berhati-hati untuk mengelakkan perlanggaran dengan antara muka lain. Mari lihat bagaimana pembangunan untuk Java menggunakan ciri ini akan berkembang.
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION