Kapan harus menggunakan: Java 8+ metode default antarmuka, vs metode abstrak

540

Java 8 memungkinkan untuk penerapan metode standar dalam antarmuka yang disebut Metode Standar .

Saya bingung antara kapan saya akan menggunakan itu interface default method, bukannya abstract class(dengan abstract method(s)).

Jadi kapan antarmuka dengan metode standar digunakan dan kapan kelas abstrak (dengan metode abstrak) digunakan? Apakah kelas abstrak masih berguna dalam skenario itu?

Narendra Pathai
sumber
38
Mungkin Anda masih tidak dapat memiliki bidang, metode pribadi, dll di antarmuka, sementara Anda bisa di kelas abstrak?
sp00m
2
Saya bertanya-tanya tentang topik ini sebelumnya, sekarang saya jelas. Terima kasih kepada @Narendra Pathai. Saya ingin menambahkan tautan utas lain yang Anda ajukan mengenai topik yang sama, karena keduanya meragukan saya. stackoverflow.com/questions/19998309/…
Ashutosh Ranjan
Anda dapat menemukan posting yang bagus untuk yang ini di sini: blog.codefx.org/java/everything-about-default-methods
Fabri Pautasso
Anda kadang-kadang masih bisa mengkode kelas dasar sebagai antarmuka bahkan jika kelas dasar memiliki status. Hanya saja antarmuka harus mendefinisikan setter dan getter untuk state dan kelas konkret harus mengimplementasikannya dan mendefinisikan field. Satu batasan untuk ini adalah bahwa dalam kelas abstrak, properti bean dapat bersifat pribadi atau dilindungi. Dalam antarmuka hanya memiliki metode publik. Jadi salah satu alasan Anda akan menggunakan kelas dasar abstrak adalah jika kelas Anda memiliki properti yang perlu pribadi atau dilindungi.
DaBlick
@DaBlick Bisakah Anda tidak memecahkan masalah negara dalam antarmuka melalui HashMap. Mis: jika Anda ingin kelas Foo yang menampung int a, b, String c. dan Anda ingin mereka memiliki status, buat HashMap </ * nama objek Foo * / String, / * peta bidang * / Hashmap </ * nama spesifik Bidang * / String, / * nilai bidang * / Objek >> peta . Ketika Anda ingin "instantiate" kelas teoritis Foo, Anda memiliki metode, instantiate (String nameOfFoo) yang melakukan map.put (nameOfFoo, bidang) di mana bidang adalah HashMap <String, Object> fields.put ("a", baru int ("5")); fields.put ("b", int baru ("6")); fields.put ("c", "bla"));
George Xavier

Jawaban:

307

Ada jauh lebih banyak untuk kelas abstrak daripada implementasi metode default (seperti negara pribadi), tetapi pada Java 8, setiap kali Anda memiliki pilihan baik, Anda harus pergi dengan metode defender (alias. default) Di antarmuka.

Kendala pada metode default adalah bahwa hal itu dapat diimplementasikan hanya dalam hal panggilan ke metode antarmuka lainnya, tanpa referensi ke keadaan implementasi tertentu. Jadi use case utama adalah metode tingkat tinggi dan kenyamanan.

Hal yang baik tentang fitur baru ini adalah bahwa, di mana sebelum Anda dipaksa untuk menggunakan kelas abstrak untuk metode kenyamanan, sehingga membatasi implementor ke warisan tunggal, sekarang Anda dapat memiliki desain yang benar-benar bersih hanya dengan antarmuka dan minimum implementasi upaya dipaksakan pada programmer.

Motivasi asli untuk memperkenalkan defaultmetode ke Java 8 adalah keinginan untuk memperluas antarmuka Collections Framework dengan metode yang berorientasi lambda tanpa merusak implementasi yang ada. Meskipun ini lebih relevan bagi penulis perpustakaan umum, Anda mungkin menemukan fitur yang sama berguna dalam proyek Anda juga. Anda punya satu tempat terpusat tempat untuk menambah kenyamanan baru dan Anda tidak harus bergantung pada bagaimana sisa dari hirarki jenis terlihat.

Marko Topolnik
sumber
34
Dengan alasan ini, hal berikutnya yang akan mereka tambahkan adalah deklarasi metode default. Saya masih tidak yakin tentang ini, fitur ini sepertinya lebih seperti hack bagi saya yang terkena semua orang untuk penyalahgunaan.
Panther
3
Satu-satunya penggunaan Kelas Abstrak di Java 8 era yang bisa saya lihat adalah untuk mendefinisikan bidang non-final. Di Antarmuka bidang secara default final sehingga Anda tidak dapat mengubahnya setelah ditetapkan.
Anuroop
7
@Anuroop Bukan hanya secara default --- itulah satu-satunya pilihan. Antarmuka tidak dapat mendeklarasikan keadaan instance, itulah mengapa kelas abstrak ada di sini untuk tetap.
Marko Topolnik
2
@ PhilipRego Metode abstrak tidak memanggil apa-apa karena tidak ada implementasi. Metode yang diterapkan dalam suatu kelas dapat mengakses status kelas (variabel instan). Antarmuka tidak dapat mendeklarasikannya sehingga metode default tidak dapat mengaksesnya. Mereka harus bergantung pada kelas yang menyediakan metode yang diimplementasikan yang mengakses negara.
Marko Topolnik
2
Marko Topolnik, jawaban Anda sudah mati. Tetapi saya ingin merekomendasikan pembaruan untuk jawaban Anda. Anda mungkin ingin menambahkan bahwa keindahan metode default adalah bahwa, jika antarmuka menambahkan metode default baru, implementasi antarmuka Anda sebelumnya tidak akan rusak. Ini tidak benar sebelum Jawa 8.
hfontanez
125

Ada beberapa perbedaan teknis. Kelas abstrak masih bisa berbuat lebih banyak dibandingkan dengan antarmuka Java 8:

  1. Kelas abstrak dapat memiliki konstruktor.
  2. Kelas abstrak lebih terstruktur dan dapat menahan keadaan.

Secara konseptual, tujuan utama metode bek adalah kompatibilitas mundur setelah pengenalan fitur-fitur baru (sebagai fungsi lambda) di Jawa 8.

Vadym Vasyliev
sumber
20
Jawaban ini sebenarnya benar dan masuk akal terutama "Secara konseptual, tujuan utama metode bek adalah kompatibilitas mundur"
Mencoba
1
@UnKnown Halaman ini memberi lebih banyak wawasan: docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html
bernie
@UnKnown, pada dasarnya memungkinkan Anda untuk menambahkan metode ke antarmuka dan kelas yang mengimplementasikan antarmuka itu secara otomatis mendapatkan fungsionalitas itu.
LegendLength
3
Poin yang lebih halus tentang poin no. 2 di atas tentang "can hold state is this". Kelas abstrak dapat menampung status yang dapat diubah kemudian. Antarmuka juga dapat menahan status tetapi setelah status ditetapkan setelah pembuatan instance, status tidak dapat diubah.
Anuroop
3
@Anuroop Saya tidak akan menggambarkan public static finalbidang antarmuka sebagai "negara". Bagian ini staticberarti bahwa mereka sama sekali tidak terkait dengan contoh tertentu. Mereka ditugaskan pada instantiation kelas , yang tidak sama dengan setelah pembuatan instance .
geronimo
65

Ini sedang dijelaskan dalam artikel ini . Pikirkan tentang forEachKoleksi.

List<?> list = 
list.forEach(…);

The forEach tidak dideklarasikan oleh java.util.Listmaupun java.util.Collectionantarmuka belum. Salah satu solusi yang jelas adalah dengan hanya menambahkan metode baru ke antarmuka yang ada dan memberikan implementasi di mana diperlukan di JDK. Namun, setelah dipublikasikan, tidak mungkin untuk menambahkan metode ke antarmuka tanpa merusak implementasi yang ada.

Manfaat yang dibawa metode default adalah sekarang mungkin menambahkan metode default baru ke antarmuka dan itu tidak merusak implementasinya.

Masudul
sumber
1
'tidak mungkin untuk menambahkan metode ke antarmuka tanpa merusak implementasi yang ada' - bukan?
Andrey Chaschev
26
@AndreyChaschev Jika Anda menambahkan metode baru ke antarmuka maka semua implementator harus menerapkan metode baru itu. Oleh karena itu merusak implementasi yang ada.
Marko Topolnik
4
@MarkoTopolnik terima kasih, melewatkannya. Hanya untuk menyebutkan ada cara untuk sebagian menghindari ini - dengan menyajikan metode ini dalam implementasi abstrak default. Untuk contoh ini ini akan AbstractList::forEachmelempar UnsupportedOperationException.
Andrey Chaschev
3
@AndreyChaschev Ya, itu cara lama (khm ... adalah cara saat ini :), dengan defisiensi yang membatasi implementor ke warisan tunggal dari implementasi abstrak yang disediakan.
Marko Topolnik
Saya tidak akan istirahat jika itu terjadi sebelumnya, semua implementasi termasuk metode itu. Yang tidak mungkin tetapi mungkin.
George Xavier
19

Keduanya sangat berbeda:

Metode default adalah menambahkan fungsionalitas eksternal ke kelas yang ada tanpa mengubah statusnya.

Dan kelas abstrak adalah jenis warisan normal , mereka adalah kelas normal yang dimaksudkan untuk diperpanjang.

Andrey Chaschev
sumber
18

Seperti yang dijelaskan dalam artikel ini ,

Kelas abstrak versus antarmuka di Java 8

Setelah memperkenalkan Metode Default, tampaknya antarmuka dan kelas abstrak sama. Namun, konsep mereka masih berbeda di Jawa 8.

Kelas abstrak dapat mendefinisikan konstruktor. Mereka lebih terstruktur dan dapat memiliki keadaan yang terkait dengannya. Sebaliknya, metode default hanya dapat diimplementasikan dalam hal memanggil metode antarmuka lainnya, tanpa referensi ke kondisi implementasi tertentu. Oleh karena itu, keduanya digunakan untuk tujuan yang berbeda dan memilih di antara keduanya benar-benar tergantung pada konteks skenario.

Sufiyan Ghori
sumber
Saya percaya kelas Abstrak memiliki Konstruktor yang dapat didefinisikan tidak seperti di Antarmuka. Di Jawa 8 mereka juga berbeda satu sama lain karena hal ini.
Hemanth Peela
1
mengapa kelas abstrak memiliki konstruktor jika tidak bisa dipakai?
George Xavier
Kita dapat memanggil super () dari kelas anak yang akan memanggil konstruktor dari kelas abstrak. Ini berdampak pada keadaan kelas abstrak.
Sujay Mohan
14

Mengenai kueri Anda tentang

Jadi kapan antarmuka dengan metode standar digunakan dan kapan kelas abstrak digunakan? Apakah kelas abstrak masih berguna dalam skenario itu?

dokumentasi java memberikan jawaban sempurna.

Kelas Abstrak Dibandingkan dengan Antarmuka:

Kelas abstrak mirip dengan antarmuka. Anda tidak dapat membuat instance mereka, dan mereka mungkin berisi campuran metode yang dinyatakan dengan atau tanpa implementasi.

Namun, dengan kelas abstrak, Anda bisa mendeklarasikan bidang yang tidak statis dan final, serta menetapkan metode konkret publik, yang dilindungi, dan pribadi.

Dengan antarmuka, semua bidang secara otomatis publik, statis, dan final, dan semua metode yang Anda nyatakan atau tentukan (sebagai metode default) bersifat publik. Selain itu, Anda dapat memperluas hanya satu kelas, baik abstrak atau tidak, sedangkan Anda dapat mengimplementasikan sejumlah antarmuka.

Gunakan kasus untuk masing-masing dari mereka telah dijelaskan di bawah posting SE:

Apa perbedaan antara antarmuka dan kelas abstrak?

Apakah kelas abstrak masih berguna dalam skenario itu?

Iya. Mereka masih berguna. Mereka dapat berisi metode dan atribut non-statis, non-final ( dilindungi, pribadi selain untuk publik ), yang tidak mungkin bahkan dengan antarmuka Java-8.

Ravindra babu
sumber
Sekarang antarmuka memiliki metode pribadi juga howtodoinjava.com/java9/java9-private-interface-methods
valijon
13

Setiap kali kita memiliki pilihan antara kelas abstrak dan antarmuka, kita harus selalu (hampir) lebih memilih metode default (juga dikenal sebagai ekstensi defender atau virtual).

  1. Metode default telah mengakhiri pola klasik antarmuka dan kelas pendamping yang mengimplementasikan sebagian besar atau semua metode di antarmuka itu. Contohnya adalah Collection and AbstractCollection. Sekarang kita harus mengimplementasikan metode dalam antarmuka itu sendiri untuk menyediakan fungsionalitas default. Kelas-kelas yang mengimplementasikan antarmuka memiliki pilihan untuk mengganti metode atau mewarisi implementasi default.
  2. Penggunaan penting lain dari metode standar adalah interface evolution. Misalkan saya memiliki Ball kelas sebagai:

    public class Ball implements Collection { ... }

Sekarang di Java 8 fitur baru di stream diperkenalkan. Kita bisa mendapatkan aliran dengan menggunakan streammetode yang ditambahkan ke antarmuka. Jika streambukan metode default semua implementasi untuk Collectionantarmuka akan rusak karena mereka tidak akan menerapkan metode baru ini. Menambahkan metode non-default ke antarmuka tidak source-compatible.

Tetapi misalkan kita tidak mengkompilasi ulang kelas dan menggunakan file jar lama yang berisi kelas ini Ball. Kelas akan memuat dengan baik tanpa metode yang hilang ini, instance dapat dibuat dan tampaknya semuanya berfungsi dengan baik. TETAPI jika program memanggil streammetode yang Ballakan kita dapatkan AbstractMethodError. Jadi membuat metode standar menyelesaikan kedua masalah tersebut.

akhil_mittal
sumber
9

Metode default di antarmuka Java memungkinkan evolusi antarmuka .

Diberikan antarmuka yang ada, jika Anda ingin menambahkan metode tanpa melanggar kompatibilitas biner dengan versi antarmuka yang lebih lama, Anda memiliki dua opsi: menambahkan metode default atau statis. Memang, setiap metode abstrak yang ditambahkan ke antarmuka harus dimasuki oleh kelas atau antarmuka yang mengimplementasikan antarmuka ini.

Metode statis adalah unik untuk suatu kelas. Metode default unik untuk turunan kelas.

Jika Anda menambahkan metode default ke antarmuka yang ada, kelas dan antarmuka yang mengimplementasikan antarmuka ini tidak perlu mengimplementasikannya. Mereka bisa

  • mengimplementasikan metode default, dan mengesampingkan implementasi dalam antarmuka yang diimplementasikan.
  • mendeklarasikan ulang metode (tanpa implementasi) yang membuatnya abstrak.
  • tidak melakukan apa-apa (maka metode default dari antarmuka yang diimplementasikan hanya diturunkan).

Lebih banyak tentang topik di sini .

Kiriloff
sumber
7

Meskipun ini adalah pertanyaan lama, izinkan saya memberi masukan untuknya juga.

  1. kelas abstrak: Di dalam kelas abstrak kita bisa mendeklarasikan variabel instan, yang diperlukan untuk kelas anak

    Antarmuka: Antarmuka di dalam setiap variabel selalu statis publik dan final, kami tidak dapat mendeklarasikan variabel instan

  2. kelas abstrak: kelas abstrak dapat berbicara tentang keadaan objek

    Antarmuka: Antarmuka tidak pernah dapat berbicara tentang keadaan objek

  3. kelas abstrak: Di dalam kelas Abstrak kita dapat mendeklarasikan konstruktor

    Antarmuka: Di dalam antarmuka kita tidak dapat mendeklarasikan konstruktor karena tujuan
    konstruktor adalah untuk menginisialisasi variabel instan. Jadi apa perlunya konstruktor di sana jika kita tidak dapat memiliki variabel instan dalam antarmuka .

  4. kelas abstrak: Di dalam kelas abstrak kita dapat mendeklarasikan instance dan blok statis

    Antarmuka: Antarmuka tidak dapat memiliki instance dan blok statis.

  5. kelas abstrak: kelas abstrak tidak dapat merujuk ekspresi lambda

    Antarmuka: Antarmuka dengan metode abstrak tunggal dapat merujuk ekspresi lambda

  6. kelas abstrak : Di dalam kelas abstrak kita dapat mengganti metode OBJECT CLASS

    Antarmuka: Kami tidak dapat mengganti metode OBJECT CLASS di dalam antarmuka.

Saya akan mengakhiri dengan catatan bahwa:

Konsep metode default / konsep metode statis dalam antarmuka datang hanya untuk menyelamatkan kelas implementasi tetapi tidak untuk memberikan implementasi bermanfaat yang bermakna. Metode default / metode statis adalah jenis implementasi dummy, "jika Anda mau, Anda dapat menggunakannya atau Anda dapat menimpanya (dalam hal metode default) di kelas implementasi" Dengan demikian menyelamatkan kami dari penerapan metode baru di kelas implementasi setiap kali metode baru di antarmuka sudah ditambahkan. Oleh karena itu antarmuka tidak pernah bisa sama dengan kelas abstrak.

Umar Tahir
sumber
5

Aturan Remi Forax adalah Anda tidak mendesain dengan kelas Abstrak. Anda mendesain aplikasi Anda dengan antarmuka . Apa pun versi Jawa, apa pun bahasanya. Hal ini didukung oleh I prinsip pemisahan nterface di SOL saya D prinsip.

Anda nanti dapat menggunakan kelas-kelas abstrak untuk memfaktisasi kode. Sekarang dengan Java 8 Anda dapat melakukannya langsung di antarmuka. Ini adalah fasilitas, tidak lebih.

Nicolas Zozol
sumber
2

kapan antarmuka dengan metode standar digunakan dan kapan kelas abstrak digunakan?

Kompatibilitas mundur: Bayangkan bahwa antarmuka Anda diimplementasikan oleh ratusan kelas, memodifikasi antarmuka itu akan memaksa semua pengguna untuk menerapkan metode yang baru ditambahkan, meskipun itu mungkin tidak penting untuk banyak kelas lain yang mengimplementasikan antarmuka Anda, Plus itu memungkinkan antarmuka Anda menjadi antarmuka fungsional

Fakta & Pembatasan:

1-Mei hanya dideklarasikan dalam antarmuka dan bukan dalam kelas atau kelas abstrak.

2-Harus menyediakan tubuh

3-Ini tidak dianggap abstrak sebagai metode normal lainnya yang digunakan dalam suatu antarmuka.

Ahmad Sanie
sumber
1

Di Java 8, antarmuka terlihat seperti kelas abstrak walaupun mungkin ada beberapa perbedaan seperti:

1) Kelas abstrak adalah kelas, sehingga tidak terbatas pada batasan antarmuka lainnya di Java, misalnya kelas abstrak dapat memiliki status , tetapi Anda tidak dapat memiliki status pada antarmuka di Jawa.

2) Perbedaan semantik lain antara antarmuka dengan metode default dan kelas abstrak adalah bahwa Anda dapat mendefinisikan konstruktor di dalam kelas abstrak , tetapi Anda tidak bisa mendefinisikan konstruktor di dalam antarmuka di Jawa

Manish Sahni
sumber
Saya setuju dengan # 2 tetapi untuk # 1, tidak bisakah Anda hanya mengimplementasikan antarmuka dan dengan demikian memiliki status melalui kelas implementasi?
George Xavier
0

Metode default di Java Interface lebih banyak digunakan untuk menyediakan implementasi dummy dari suatu fungsi sehingga menghemat kelas implementasi dari antarmuka itu dari rasa sakit menyatakan semua metode abstrak bahkan jika mereka ingin berurusan dengan hanya satu. Metode standar dalam antarmuka dengan demikian lebih merupakan pengganti konsep kelas adaptor.

Metode dalam kelas abstrak seharusnya memberikan implementasi yang bermakna dimana setiap kelas anak harus menimpa hanya jika diperlukan untuk menimpa fungsionalitas umum.

shubh
sumber
0

Seperti disebutkan dalam jawaban lain, kemampuan untuk menambahkan implementasi ke antarmuka ditambahkan untuk memberikan kompatibilitas mundur dalam kerangka kerja Koleksi. Saya berpendapat bahwa memberikan kompatibilitas ke belakang berpotensi satu-satunya alasan yang baik untuk menambahkan implementasi ke antarmuka.

Jika tidak, jika Anda menambahkan implementasi ke antarmuka, Anda melanggar hukum dasar mengapa antarmuka ditambahkan di tempat pertama. Java adalah bahasa pewarisan tunggal, tidak seperti C ++ yang memungkinkan untuk pewarisan berganda. Antarmuka memberikan manfaat pengetikan yang datang dengan bahasa yang mendukung multiple inheritance tanpa memperkenalkan masalah yang datang dengan multiple inheritance.

Lebih khusus lagi, Java hanya memungkinkan pewarisan tunggal dari suatu implementasi, tetapi memang memungkinkan banyak pewarisan antarmuka. Misalnya, berikut ini adalah kode Java yang valid:

class MyObject extends String implements Runnable, Comparable { ... }

MyObject hanya mewarisi satu implementasi, tetapi mewarisi tiga kontrak.

Java meneruskan beberapa warisan implementasi karena beberapa warisan implementasi disertai dengan sejumlah masalah pelik, yang berada di luar cakupan jawaban ini. Antarmuka ditambahkan untuk memungkinkan multiple inheritance of contract (alias antarmuka) tanpa masalah multiple inheritance of implementation.

Untuk mendukung pendapat saya, berikut adalah kutipan dari Ken Arnold dan James Gosling dari buku The Java Programming Language, edisi ke-4 :

Warisan tunggal menghalangi beberapa desain yang berguna dan benar. Masalah multiple inheritance muncul dari multiple inheritance implementasi, tetapi dalam banyak kasus multiple inheritance digunakan untuk mewarisi sejumlah kontrak abstrak dan mungkin satu implementasi konkret. Menyediakan sarana untuk mewarisi kontrak abstrak tanpa mewarisi implementasi memungkinkan manfaat pengetikan multiple inheritance tanpa masalah banyak warisan implementasi. Warisan kontrak abstrak disebut pewarisan antarmuka . Bahasa pemrograman Java mendukung pewarisan antarmuka dengan memungkinkan Anda mendeklarasikan suatu interfacetipe

johnnyodonnell
sumber
-1

Tolong pikirkan dulu prinsip buka / tutup. Metode default di antarmuka DO VIOLATE itu. Ini adalah fitur buruk di Java. Ini mendorong desain yang buruk, arsitektur yang buruk, kualitas perangkat lunak yang rendah. Saya akan menyarankan untuk menghindari menggunakan metode standar sepenuhnya.

Ajukan beberapa pertanyaan kepada diri sendiri: Mengapa Anda tidak bisa memasukkan metode Anda ke kelas abstrak? Apakah Anda memerlukan lebih dari satu kelas abstrak? Kemudian pikirkan tentang apa yang menjadi tanggung jawab kelas Anda. Apakah Anda yakin semua metode yang akan Anda masukkan ke kelas tunggal benar-benar memenuhi tujuan yang sama? Mungkin Anda akan membedakan beberapa tujuan dan kemudian akan membagi kelas Anda menjadi beberapa kelas, untuk setiap tujuan kelasnya sendiri.

mentallurg
sumber