Mengapa ada metode default?
Java 8 akan datang. Seperti yang disebutkan sebelumnya, kami telah membahas banyak tentang tema ini sebelumnya, tetapi ekspresi Lambdas bukan satu -satunya perubahan aturan permainan di Java 8.
Misalkan Java 8 telah dilepaskan dan mengandung lambda. Sekarang Anda berencana untuk menggunakan lambda.
Daftar <?> Daftar = ... Daftar.Faceach (...); // Ini adalah kode lambda
Definisi foreach tidak dapat ditemukan di java.util.list atau java.util.collection. Biasanya merupakan solusi untuk menambahkan metode dan implementasi baru ke antarmuka yang relevan di JDK. Namun, untuk rilis rilis, tidak mungkin untuk menambahkan metode baru ke antarmuka sementara tidak mempengaruhi implementasi yang ada.
Oleh karena itu, jika lambda digunakan di Java 8, tidak mungkin digunakan untuk pustaka koleksi karena kompatibilitas ke depan.
Untuk alasan di atas, konsep baru diperkenalkan. Metode ekstensi virtual, yang biasanya merupakan metode pertahanan, sekarang dapat ditambahkan ke antarmuka, sehingga implementasi default dari perilaku pernyataan tersebut dapat disediakan.
Sederhananya, antarmuka Java sekarang dapat mengimplementasikan metode ini. Keuntungan dari metode default adalah dapat menambahkan metode default baru ke antarmuka tanpa menghancurkan implementasi antarmuka.
Menurut pendapat saya, ini bukan jenis karakteristik Java yang akan digunakan setiap hari, tetapi pasti dapat menggunakan Lambda untuk menggunakan Lambda secara alami.
Contoh paling sederhana
Mari kita lihat contoh paling sederhana: antarmuka A, kelas Clazz mengimplementasikan antarmuka A.
Antarmuka publik A {default void foo () {System.out.println ("Calling A.Foo ()");} kelas kelas publik kelas A {}Kode dapat dikompilasi, bahkan jika kelas Clazz tidak mengimplementasikan metode FOO (). Implementasi default dari metode FOO () disediakan dalam antarmuka A.
Kode klien menggunakan contoh ini:
Clazz clazz = new clazz ();
Warisan berganda?
Ada pertanyaan umum: Orang akan bertanya ketika mereka pertama kali mendengar fitur -fitur baru dari metode default "" Jika suatu kelas mengimplementasikan dua antarmuka, dan kedua antarmuka mendefinisikan metode default dengan tanda tangan yang sama. dengan contoh sebelumnya:
Antarmuka publik A {default void foo () {System.out.println ("Calling A.Foo ()");Kode ini tidak dapat menyusun alasan berikut:
Java: Kelas Clazz dari tipe A ke B ke foo () mewarisi nilai default yang tidak terkait
Untuk memperbaiki ini, di Clazz, kita harus menyelesaikan metode penulisan ulang konflik secara manual:
Public Class Clazz mengimplementasikan A, B {public void foo () {}}} Tetapi apa yang harus kita lakukan jika kita ingin memanggil metode implementasi default dari antarmuka A, alih -alih mengimplementasikan metode kita sendiri? Ini dimungkinkan, kutip foo () dalam a, seperti yang ditunjukkan di bawah ini:
Kelas publik Clazz mengimplementasikan A, B {public void foo () {a.super.foo ();}}} Sekarang saya tidak bisa sangat yakin bahwa saya suka solusi akhir ini. Mungkin lebih ringkas daripada realisasi metode default dalam tanda tangan, seperti yang dinyatakan dalam draft pertama spesifikasi metode default:
Public Class Clazz mengimplementasikan A, B {public void foo () default a.foo;}Tapi ini mengubah tata bahasa, bukan? Jika antarmuka A dan antarmuka B mendefinisikan banyak metode default yang saling bertentangan, dan saya bersedia menggunakan metode default dari semua antarmuka A untuk menyelesaikan konflik? Saat ini, saya harus menyelesaikan konflik satu demi satu untuk menulis ulang setiap pasangan konflik. Ini mungkin memerlukan banyak pekerjaan dan menulis sejumlah besar kode template.
Saya memperkirakan bahwa metode penyelesaian konflik membutuhkan banyak diskusi, tetapi tampaknya pencipta memutuskan untuk menerima bencana yang tidak dapat dihindari.
Contoh nyata
Contoh nyata dari metode default dapat ditemukan di tas awal JDK8. Kembali ke contoh metode pengumpulan koleksi, kita dapat menemukan bahwa di antarmuka java.lang.itible, implementasinya yang default adalah sebagai berikut:
@FunctionInterfacepublic Interface iterable <T> {iterator <T> iterator (); Foreach menggunakan parameter java.util.function.consumer Tipe Antarmuka Fungsi, yang memungkinkan kita untuk melewati ekspresi lambda atau referensi metode, sebagai berikut:
Daftar <?> Daftar = ... Daftar.Faceach (System.out :: println);
Panggilan metode
Mari kita lihat bagaimana metode default sebenarnya disebut. Jika Anda tidak terbiasa dengan masalah ini, maka Anda mungkin tertarik membaca Rebel Labs tentang java byte.
Dari perspektif kode klien, metode default hanyalah metode virtual umum. Oleh karena itu, nama harus menjadi metode ekstensi virtual. Oleh karena itu, untuk contoh sederhana dari metode default sebagai antarmuka, kode klien akan secara otomatis memanggil antarmuka di tempat di mana metode default dipanggil.
A clazz = new clazz ();
Jika konflik metode default telah diselesaikan, maka ketika kami memodifikasi metode default dan menentukan salah satu antarmuka, InvokeSpecial akan menentukan implementasi dari implementasi antarmuka dari panggilan spesifik.
Public Class Clazz mengimplementasikan A, B {public void foo () {a.super.foo (); Berikut ini adalah output dari JAVAP:
public void foo ();; 0: aload_01: Invokespecial #2 // Interfacemethod A.foo: / () V4: Return: Return
Seperti yang Anda lihat: Instruksi Invokespecial digunakan untuk memanggil metode antarmuka FOO (). Dari perspektif bytecode, ini masih merupakan hal baru, karena sebelum Anda hanya dapat memanggil metode dengan menunjuk ke kelas (induk) alih -alih super yang menunjuk ke antarmuka.
akhirnya…
Metode default adalah suplemen yang menarik untuk bahasa Java. Tujuan utama dari ekspresi default adalah untuk mengembangkan antarmuka JDK standar, dan ketika kami akhirnya mulai menggunakan ekspresi Lambdas Java 8, kami memberi kami pengalaman transisi yang lancar. Siapa tahu, mungkin kita akan melihat lebih banyak metode default dalam desain API di masa depan.