Saya tahu bahwa multiple inheritance tidak diperbolehkan di Java dan C #. Banyak buku hanya mengatakan, pewarisan ganda tidak diperbolehkan. Tapi itu bisa diimplementasikan dengan menggunakan antarmuka. Tidak ada yang dibahas tentang mengapa itu tidak diperbolehkan. Adakah yang bisa memberi tahu saya dengan tepat mengapa itu tidak diizinkan?
c#
java
language-design
multiple-inheritance
Abdulsattar Mohammed
sumber
sumber
Jawaban:
Jawaban singkatnya adalah: karena desainer bahasa memutuskan untuk tidak melakukannya.
Pada dasarnya, tampaknya desainer .NET dan Java tidak mengizinkan banyak pewarisan karena mereka beralasan bahwa menambahkan MI menambahkan terlalu banyak kerumitan pada bahasa sambil memberikan manfaat yang terlalu sedikit .
Untuk bacaan yang lebih menyenangkan dan mendalam, ada beberapa artikel yang tersedia di web dengan wawancara dari beberapa desainer bahasa. Misalnya, untuk .NET, Chris Brumme (yang bekerja di MS pada CLR) telah menjelaskan alasan mengapa mereka memutuskan untuk tidak:
Anda dapat membaca artikel lengkapnya di sini.
Untuk Java, Anda bisa membaca artikel ini :
sumber
Beberapa pewarisan implementasi adalah apa yang tidak diperbolehkan.
Masalahnya adalah bahwa compiler / runtime tidak dapat menemukan apa yang harus dilakukan jika Anda memiliki kelas Cowboy dan Artist, keduanya dengan implementasi untuk metode draw (), dan kemudian Anda mencoba untuk membuat tipe CowboyArtist baru. Apa yang terjadi ketika Anda memanggil metode draw ()? Apakah seseorang tergeletak mati di jalan, atau apakah Anda memiliki cat air yang indah?
Saya percaya itu disebut masalah warisan berlian ganda.
sumber
Alasan: Java sangat populer dan mudah dikodekan, karena kesederhanaannya.
Jadi apa pun yang dirasa pengembang java sulit dan rumit untuk dipahami oleh programmer, mereka berusaha menghindarinya. Salah satu jenis properti tersebut adalah multiple inheritance.
Masalah dengan banyak warisan: Masalah berlian.
Contoh :
Ini adalah ambiguitas yang ada dalam masalah intan.
Bukan tidak mungkin untuk memecahkan masalah ini, tetapi ini menciptakan lebih banyak kebingungan dan kerumitan bagi programmer saat membacanya. Itu menyebabkan lebih banyak masalah daripada yang coba dipecahkan.
Catatan : Tapi dengan cara apapun Anda selalu bisa mengimplementasikan beberapa warisan secara tidak langsung dengan menggunakan antarmuka.
sumber
Karena Java memiliki filosofi desain yang sangat berbeda dari C ++. (Saya tidak akan membahas C # di sini.)
Dalam mendesain C ++, Stroustrup ingin menyertakan fitur yang berguna, terlepas dari bagaimana fitur tersebut dapat disalahgunakan. Mungkin untuk mengacaukan banyak waktu dengan beberapa warisan, kelebihan operator, templat, dan berbagai fitur lainnya, tetapi mungkin juga untuk melakukan beberapa hal yang sangat baik dengannya.
Filosofi desain Java adalah untuk menekankan keamanan dalam konstruksi bahasa. Hasilnya adalah ada hal-hal yang jauh lebih canggung untuk dilakukan, tetapi Anda bisa lebih yakin bahwa kode yang Anda lihat memiliki arti seperti yang Anda pikirkan.
Selanjutnya, Java sebagian besar merupakan reaksi dari C ++ dan Smalltalk, bahasa OO yang paling terkenal. Ada banyak bahasa OO lainnya (Common Lisp sebenarnya adalah bahasa pertama yang distandarisasi), dengan sistem OO berbeda yang menangani MI dengan lebih baik.
Belum lagi MI di Java sangat mungkin dilakukan, menggunakan antarmuka, komposisi, dan delegasi. Ini lebih eksplisit daripada di C ++, dan oleh karena itu lebih canggung untuk digunakan tetapi akan memberi Anda sesuatu yang lebih mungkin Anda pahami pada pandangan pertama.
Tidak ada jawaban yang benar disini. Ada jawaban yang berbeda, dan mana yang lebih baik untuk situasi tertentu bergantung pada aplikasi dan preferensi individu.
sumber
Alasan utama (meskipun bukan satu-satunya) alasan orang menjauh dari MI adalah apa yang disebut "masalah berlian" yang menyebabkan ambiguitas dalam implementasi Anda. Ini artikel wikipedia membahas dan menjelaskan lebih baik daripada aku bisa. MI juga dapat menyebabkan kode yang lebih kompleks, dan banyak desainer OO mengklaim bahwa Anda tidak memerlukan MI, dan jika Anda menggunakannya, model Anda mungkin salah. Saya tidak yakin saya setuju dengan poin terakhir ini, tetapi menjaga hal-hal sederhana selalu merupakan rencana yang baik.
sumber
Dalam C ++ multiple inheritance merupakan sakit kepala besar bila digunakan secara tidak benar. Untuk menghindari masalah desain populer itu, beberapa antarmuka "warisan" dipaksa sebagai gantinya dalam bahasa modern (java, C #).
sumber
Warisan Ganda adalah
Oleh karena itu, dapat dianggap sebagai pilihan bijak untuk tidak memasukkan Warisan Ganda ke dalam bahasa Java.
sumber
Alasan lain adalah bahwa pewarisan tunggal membuat casting menjadi sepele, tanpa mengeluarkan instruksi assembler (selain memeriksa kompatibilitas jenis yang diperlukan). Jika Anda memiliki multiple-inheritance, Anda perlu mencari tahu di mana di kelas anak induk tertentu dimulai. Jadi kinerja tentu saja merembes (meski bukan satu-satunya).
sumber
Kembali ke masa lalu (70-an) ketika Ilmu Komputer lebih banyak Ilmu dan kurang produksi massal programmer punya waktu untuk memikirkan desain yang baik dan implementasi yang baik dan sebagai hasilnya produk (program) memiliki kualitas tinggi (misalnya desain TCP / IP dan implementasi). Saat ini, ketika semua orang memprogram, dan manajer mengubah spesifikasi sebelum tenggat waktu, masalah halus seperti yang dijelaskan di tautan wikipedia dari posting Steve Haigh sulit dilacak; oleh karena itu, "multiple inheritance" dibatasi oleh desain kompilator. Jika Anda suka, Anda masih dapat menggunakan C ++ .... dan memiliki semua kebebasan yang Anda inginkan :)
sumber
Saya mengambil pernyataan bahwa "Warisan ganda tidak diperbolehkan di Java" dengan sedikit garam.
Beberapa Warisan didefinisikan ketika "Jenis" mewarisi dari lebih dari satu "Jenis". Dan antarmuka juga diklasifikasikan sebagai tipe karena memiliki perilaku. Jadi Java memang memiliki banyak warisan. Hanya saja itu lebih aman.
sumber
Pemuatan kelas yang dinamis membuat implementasi multiple inheritance menjadi sulit.
Di java sebenarnya mereka menghindari kompleksitas multiple inheritance dengan menggunakan single inheritance dan interface. Kompleksitas multiple inheritance sangat tinggi dalam situasi seperti yang dijelaskan di bawah ini
masalah berlian dari banyak warisan. Kami memiliki dua kelas B dan C yang diturunkan dari A. Asumsikan bahwa B dan C menimpa metode yang diwariskan dan mereka menyediakan implementasinya sendiri. Sekarang D mewarisi dari B dan C melakukan multiple inheritance. D harus mewarisi metode yang ditimpa, jvm tidak dapat memutuskan metode mana yang akan digunakan?
Di c ++ fungsi virtual digunakan untuk menangani dan kita harus melakukannya secara eksplisit.
Ini dapat dihindari dengan menggunakan antarmuka, tidak ada badan metode. Antarmuka tidak dapat dibuat instance-nya — ia hanya dapat diterapkan oleh kelas atau diperluas oleh antarmuka lain.
sumber
Sebenarnya multiple inheritance akan menimbulkan kompleksitas jika kelas yang diturunkan memiliki fungsi yang sama. yaitu kompilator akan bingung mana yang harus dipilih (masalah berlian). Jadi di Java kompleksitas itu dihapus dan memberi antarmuka untuk mendapatkan fungsionalitas seperti yang diberikan oleh banyak warisan. Kita bisa menggunakan interface
sumber
Java memiliki konsep yaitu polimorfisme. Ada 2 jenis polimorfisme di Jawa. Ada metode overloading dan metode overriding. Di antara mereka, penggantian metode terjadi dengan hubungan super- dan subclass. Jika kita membuat objek subclass dan menjalankan metode superclass, dan jika subclass memanjang lebih dari satu kelas, metode kelas super mana yang harus dipanggil?
Atau, saat memanggil konstruktor superclass
super()
, konstruktor kelas super mana yang akan dipanggil?Keputusan ini tidak mungkin dilakukan oleh fitur API java saat ini. jadi multiple inheritance tidak diperbolehkan di java.
sumber
Warisan Ganda tidak diizinkan di Java secara langsung, tetapi melalui antarmuka diizinkan.
Alasan:
Warisan Ganda: Memperkenalkan lebih banyak kompleksitas dan ambiguitas.
Antarmuka: Antarmuka adalah kelas yang sepenuhnya abstrak di Java yang memberi Anda cara seragam untuk menggambarkan struktur atau cara kerja bagian dalam program Anda dengan benar dari antarmuka yang tersedia untuk umum, dengan konsekuensi menjadi lebih banyak fleksibilitas dan kode yang dapat digunakan kembali serta lebih banyak kontrol tentang cara Anda membuat dan berinteraksi dengan kelas lain.
Lebih tepatnya, mereka adalah konstruksi khusus di Java dengan karakteristik tambahan yang memungkinkan Anda untuk melakukan semacam pewarisan berganda yaitu kelas yang dapat dikirim ke lebih dari satu kelas.
Mari kita ambil contoh sederhana.
Misalkan ada 2 kelas super kelas A dan B dengan nama metode yang sama tetapi fungsionalitas yang berbeda. Melalui kode berikut dengan (memperluas) beberapa pewarisan kata kunci tidak mungkin.
Tetapi melalui antarmuka, dengan (mengimplementasikan) kata kunci banyak pewarisan dimungkinkan.
sumber
Anda dapat menemukan jawabannya dari tautan dokumentasi ini
Jika beberapa pewarisan diperbolehkan dan saat Anda membuat objek dengan membuat instance kelas itu, objek itu akan mewarisi bidang dari semua kelas super kelas. Ini akan menyebabkan dua masalah.
Bagaimana jika metode atau konstruktor dari kelas super berbeda membuat instance bidang yang sama?
Metode atau konstruktor mana yang akan diutamakan?
Meskipun beberapa pewarisan status sekarang diizinkan, Anda tetap dapat menerapkan
Jenis warisan berganda : Kemampuan kelas untuk mengimplementasikan lebih dari satu antarmuka.
Beberapa pewarisan implementasi (melalui metode default di antarmuka): Kemampuan untuk mewarisi definisi metode dari beberapa kelas
Lihat pertanyaan SE terkait ini untuk info tambahan:
Beberapa Ambiguitas Warisan dengan Antarmuka
sumber
Dalam C ++ kelas dapat mewarisi (secara langsung atau tidak langsung) dari lebih dari satu kelas, yang disebut sebagai warisan berganda .
C # dan Java, bagaimanapun, membatasi kelas ke satu warisan yang diwarisi setiap kelas dari kelas induk tunggal.
Beberapa pewarisan adalah cara yang berguna untuk membuat kelas yang menggabungkan aspek dari dua hierarki kelas yang berbeda, sesuatu yang sering terjadi saat menggunakan kerangka kelas yang berbeda dalam satu aplikasi.
Jika dua kerangka kerja menentukan kelas dasarnya sendiri untuk pengecualian, misalnya, Anda dapat menggunakan beberapa pewarisan untuk membuat kelas pengecualian yang dapat digunakan dengan salah satu kerangka kerja.
Masalah dengan multiple inheritance adalah hal itu dapat menyebabkan ambiguitas. Contoh klasiknya adalah ketika sebuah kelas mewarisi dari dua kelas lainnya, yang masing-masing mewarisi dari kelas yang sama:
Dalam contoh ini,
flag
anggota data ditentukan olehclass A
. Tapiclass D
turun dariclass B
danclass C
, yang keduanya berasal dariA
, jadi pada dasarnya dua salinan dariflag
yang tersedia karena dua contohA
dalamD
hirarki kelas 's. Mana yang mau Anda setel? Kompilator akan mengeluh bahwa referensi keflag
dalamD
bersifat ambigu . Salah satu cara memperbaikinya adalah dengan menguraikan referensi secara eksplisit:Perbaikan lainnya adalah dengan mendeklarasikan B dan C sebagai
virtual base classes
, yang berarti bahwa hanya satu salinan A yang dapat berada dalam hierarki, menghilangkan ambiguitas.Kompleksitas lain ada dengan beberapa pewarisan, seperti urutan di mana kelas dasar diinisialisasi saat objek turunan dibangun, atau cara anggota dapat secara tidak sengaja disembunyikan dari kelas turunan. Untuk menghindari kerumitan ini, beberapa bahasa membatasi diri pada model pewarisan tunggal yang lebih sederhana.
Meskipun ini sangat menyederhanakan pewarisan, kegunaannya juga terbatas karena hanya kelas dengan leluhur yang sama yang dapat berbagi perilaku. Antarmuka mengurangi pembatasan ini dengan mengizinkan kelas dalam hierarki yang berbeda untuk mengekspos antarmuka umum meskipun tidak diimplementasikan dengan berbagi kode.
sumber
Bayangkan Contoh ini: Saya punya kelas
Shape1
Ini memiliki
CalcualteArea
metode:Ada kelas lain
Shape2
yang juga memiliki metode yang samaSekarang saya memiliki Circle kelas anak, itu berasal dari Shape1 dan Shape2;
Sekarang ketika saya membuat objek untuk Circle, dan memanggil metode tersebut, sistem tidak tahu metode menghitung luas mana yang akan dipanggil. Keduanya memiliki tanda tangan yang sama. Jadi compiler akan bingung. Itu sebabnya banyak warisan tidak diperbolehkan.
Tetapi mungkin ada banyak antarmuka karena antarmuka tidak memiliki definisi metode. Meskipun kedua antarmuka memiliki metode yang sama, keduanya tidak memiliki implementasi apa pun dan selalu metode di kelas anak akan dijalankan.
sumber