Java tidak mengizinkan banyak pewarisan, tetapi memungkinkan implementasi beberapa antarmuka. Mengapa?
Java tidak mengizinkan banyak pewarisan, tetapi memungkinkan implementasi beberapa antarmuka. Mengapa?
Jawaban:
Karena antarmuka hanya menentukan apa yang dikerjakan kelas, bukan bagaimana melakukannya.
Masalah dengan multiple inheritance adalah bahwa dua kelas dapat mendefinisikan cara berbeda untuk melakukan hal yang sama, dan subclass tidak dapat memilih mana yang akan dipilih.
Salah satu instruktur perguruan tinggi saya menjelaskan kepada saya seperti ini:
Misalkan saya memiliki satu kelas, yaitu pemanggang roti, dan kelas lain, yaitu NuclearBomb. Mereka berdua mungkin memiliki pengaturan "kegelapan". Keduanya memiliki metode on (). (Satu memiliki off (), yang lain tidak.) Jika saya ingin membuat kelas yang merupakan subkelas dari kedua ... seperti yang Anda lihat, ini adalah masalah yang benar-benar bisa meledak di wajah saya di sini .
Jadi salah satu masalah utama adalah jika Anda memiliki dua kelas induk, mereka mungkin memiliki implementasi yang berbeda dari fitur yang sama - atau mungkin dua fitur berbeda dengan nama yang sama, seperti dalam contoh instruktur saya. Maka Anda harus berurusan dengan memutuskan mana subclass Anda akan digunakan. Ada beberapa cara untuk menangani hal ini, tentu saja - C ++ melakukannya - tetapi para perancang Jawa merasa bahwa ini akan membuat segalanya menjadi terlalu rumit.
Dengan antarmuka, Anda menggambarkan sesuatu yang mampu dilakukan oleh kelas, daripada meminjam metode kelas lain untuk melakukan sesuatu. Beberapa antarmuka jauh lebih kecil kemungkinannya menyebabkan konflik rumit yang perlu diselesaikan daripada beberapa kelas induk.
Karena warisan terlalu sering digunakan bahkan ketika Anda tidak bisa mengatakan "hei, metode itu terlihat berguna, saya akan memperpanjang kelas itu juga".
public class MyGodClass extends AppDomainObject, HttpServlet, MouseAdapter,
AbstractTableModel, AbstractListModel, AbstractList, AbstractMap, ...
Jawaban dari pertanyaan ini terletak pada kerja internal kompiler java (konstruktor chaining). Jika kita melihat kerja internal kompiler java:
public class Bank {
public void printBankBalance(){
System.out.println("10k");
}
}
class SBI extends Bank{
public void printBankBalance(){
System.out.println("20k");
}
}
Setelah mengkompilasi ini terlihat seperti:
public class Bank {
public Bank(){
super();
}
public void printBankBalance(){
System.out.println("10k");
}
}
class SBI extends Bank {
SBI(){
super();
}
public void printBankBalance(){
System.out.println("20k");
}
}
ketika kita memperluas kelas dan membuat objeknya, satu rantai konstruktor akan berjalan hingga Object
kelas.
Kode di atas akan berjalan dengan baik. tetapi jika kita memiliki kelas lain yang disebut Car
memanjang Bank
dan satu kelas hybrid (multiple inheritance) disebut SBICar
:
class Car extends Bank {
Car() {
super();
}
public void run(){
System.out.println("99Km/h");
}
}
class SBICar extends Bank, Car {
SBICar() {
super(); //NOTE: compile time ambiguity.
}
public void run() {
System.out.println("99Km/h");
}
public void printBankBalance(){
System.out.println("20k");
}
}
Dalam hal ini (SBICar) akan gagal membuat rantai konstruktor ( kompilasi ambiguitas waktu ).
Untuk antarmuka ini diizinkan karena kami tidak dapat membuat objek darinya.
Untuk konsep default
dan static
metode baru silakan merujuk default di antarmuka .
Semoga ini akan menyelesaikan pertanyaan Anda. Terima kasih.
Menerapkan banyak antarmuka sangat berguna dan tidak menyebabkan banyak masalah bagi pelaksana bahasa maupun programmer. Jadi itu diizinkan. Berbagai warisan sementara juga bermanfaat, dapat menyebabkan masalah serius bagi pengguna ( berlian kematian yang ditakuti ). Dan sebagian besar hal yang Anda lakukan dengan pewarisan berganda juga dapat dilakukan dengan komposisi atau menggunakan kelas batin. Jadi multiple inheritance dilarang membawa lebih banyak masalah daripada keuntungan.
ToyotaCar
dan HybridCar
keduanya berasal dari Car
dan mengesampingkan Car.Drive
, dan jika PriusCar
mewarisi keduanya tetapi tidak mengesampingkanDrive
, sistem tidak akan memiliki cara untuk mengidentifikasi apa yang Car.Drive
harus dilakukan virtual . Antarmuka menghindari masalah ini dengan menghindari kondisi miring di atas.
void UseCar(Car &foo)
; tidak dapat diharapkan untuk memasukkan disambiguasi antara ToyotaCar::Drive
dan HybridCar::Drive
(karena seharusnya sering tidak mengetahui atau peduli bahwa jenis-jenis lain bahkan ada ) Suatu bahasa dapat, seperti halnya C ++, memerlukan kode yang ToyotaCar &myCar
ingin meneruskannya UseCar
terlebih dahulu harus dilemparkan ke salah satu HybridCar
atau ToyotaCar
, tetapi karena ((Mobil) (HybridCar) myCar) .Drive` dan ((Car)(ToyotaCar)myCar).Drive
akan melakukan hal yang berbeda, yang akan menyiratkan bahwa upcasts tidak melestarikan identitas.
Anda dapat menemukan jawaban yang akurat untuk kueri ini di halaman dokumentasi oracle tentang multiple inheritance
Multiple inheritance of state: Kemampuan untuk mewarisi bidang dari beberapa kelas
Salah satu alasan mengapa bahasa pemrograman Java tidak memungkinkan Anda untuk memperluas lebih dari satu kelas adalah untuk menghindari masalah multiple inheritance of state, yang merupakan kemampuan untuk mewarisi bidang dari beberapa kelas
Jika beberapa pewarisan diizinkan dan Saat Anda membuat objek dengan membuat instance kelas itu, objek itu akan mewarisi bidang dari semua superclasses kelas. Itu akan menyebabkan dua masalah.
Berbagai warisan implementasi: Kemampuan untuk mewarisi definisi metode dari beberapa kelas
Masalah dengan pendekatan ini: konflik nama dan ambiguitas . Jika subkelas dan superclass berisi nama metode (dan tanda tangan) yang sama, kompiler tidak dapat menentukan versi yang akan dipanggil.
Tetapi java mendukung tipe multiple inheritance ini dengan metode default , yang telah diperkenalkan sejak rilis Java 8. Kompiler Java menyediakan beberapa aturan untuk menentukan metode default mana yang digunakan kelas tertentu.
Lihat posting SE di bawah ini untuk detail lebih lanjut tentang menyelesaikan masalah berlian:
Multiple inheritance of type: Kemampuan suatu kelas untuk mengimplementasikan lebih dari satu antarmuka.
Karena antarmuka tidak mengandung bidang yang dapat diubah, Anda tidak perlu khawatir tentang masalah yang timbul dari banyak pewarisan status di sini.
Dikatakan bahwa objek state disebut sehubungan dengan bidang di dalamnya dan itu akan menjadi ambigu jika terlalu banyak kelas diwarisi. Ini tautannya
http://docs.oracle.com/javase/tutorial/java/IandI/multipleinheritance.html
Java mendukung banyak pewarisan melalui antarmuka saja. Kelas dapat mengimplementasikan sejumlah antarmuka tetapi hanya dapat memperluas satu kelas.
Warisan berganda tidak didukung karena menyebabkan masalah berlian yang mematikan. Namun, ini dapat diselesaikan tetapi mengarah ke sistem yang kompleks sehingga banyak warisan telah dijatuhkan oleh para pendiri Java.
Dalam sebuah buku putih berjudul “Java: an Overview” oleh James Gosling pada Februari 1995 ( tautan ) memberikan gambaran mengapa banyak warisan tidak didukung di Jawa.
Menurut Gosling:
"JAVA menghilangkan banyak fitur C ++ yang jarang digunakan, kurang dipahami, membingungkan, yang dalam pengalaman kami membawa lebih banyak kesedihan daripada manfaat. Ini terutama terdiri dari kelebihan operator (meskipun memiliki kelebihan metode), banyak pewarisan, dan pemaksaan otomatis yang ekstensif."
Untuk alasan yang sama C # tidak memungkinkan pewarisan berganda tetapi memungkinkan Anda untuk mengimplementasikan beberapa antarmuka.
Pelajaran yang dapat dipetik dari C ++ w / multiple inheritence adalah bahwa hal itu menyebabkan lebih banyak masalah daripada nilainya.
Antarmuka adalah kontrak hal-hal yang harus diimplementasikan oleh kelas Anda. Anda tidak mendapatkan fungsionalitas apa pun dari antarmuka. Inheritence memungkinkan Anda untuk mewarisi fungsi kelas induk (dan dalam multiple-inheritence, itu bisa sangat membingungkan).
Mengizinkan banyak antarmuka memungkinkan Anda untuk menggunakan Pola Desain (seperti Adaptor) untuk memecahkan jenis masalah yang sama yang dapat Anda pecahkan dengan menggunakan pewarisan berganda, tetapi dengan cara yang jauh lebih andal dan dapat diprediksi.
D1
dan D2
keduanya mewarisi dari B
, dan masing-masing menimpa fungsi f
, dan jika obj
adalah sebuah instance dari tipe S
yang mewarisi dari keduanya D1
dan D2
tetapi tidak menimpa f
, maka casting referensi S
ke D1
harus menghasilkan sesuatu yang f
menggunakan D1
override, dan casting untuk B
tidak boleh ganti itu. Demikian juga pengecoran referensi S
untuk D2
harus menghasilkan sesuatu yang f
menggunakan yang D2
menimpa, dan casting untuk B
tidak harus mengubah itu. Jika suatu bahasa tidak perlu memperbolehkan anggota virtual untuk ditambahkan ...
Karena topik ini tidak dekat, saya akan memposting jawaban ini, saya harap ini membantu seseorang untuk memahami mengapa java tidak memungkinkan banyak pewarisan.
Pertimbangkan kelas berikut:
public class Abc{
public void doSomething(){
}
}
Dalam hal ini kelas Abc tidak memperluas apa-apa, bukan? Tidak begitu cepat, kelas ini secara implisit memperluas Object kelas, kelas dasar yang memungkinkan semuanya berfungsi di java. Semuanya adalah objek.
Jika Anda mencoba untuk menggunakan kelas atas Anda akan melihat bahwa IDE Anda memungkinkan Anda untuk menggunakan metode seperti: equals(Object o)
, toString()
, dll, tetapi Anda tidak menyatakan metode tersebut, mereka datang dari kelas dasarObject
Kamu bisa mencoba:
public class Abc extends String{
public void doSomething(){
}
}
Ini baik-baik saja, karena kelas Anda tidak akan implisit meluas Object
tetapi akan meluas String
karena Anda mengatakannya. Pertimbangkan perubahan berikut:
public class Abc{
public void doSomething(){
}
@Override
public String toString(){
return "hello";
}
}
Sekarang kelas Anda akan selalu mengembalikan "halo" jika Anda memanggil toString ().
Sekarang bayangkan kelas berikut:
public class Flyer{
public void makeFly(){
}
}
public class Bird extends Abc, Flyer{
public void doAnotherThing(){
}
}
Sekali lagi kelas Flyer
implisit extends Object yang memiliki metode toString()
, setiap kelas akan memiliki metode ini karena mereka semua diperluas Object
secara tidak langsung, jadi, jika Anda menelepon toString()
dari Bird
, toString()
java mana yang harus digunakan? Dari Abc
atau Flyer
? Ini akan terjadi dengan setiap kelas yang mencoba memperluas dua atau lebih kelas, untuk menghindari "metode tabrakan" semacam ini mereka membangun ide antarmuka , pada dasarnya Anda bisa menganggapnya sebagai kelas abstrak yang tidak memperluas Obyek secara tidak langsung . Karena mereka abstrak, mereka harus diimplementasikan oleh sebuah kelas, yang merupakan objek(Anda tidak dapat membuat antarmuka saja, mereka harus diimplementasikan oleh sebuah kelas), sehingga semuanya akan terus berfungsi dengan baik.
Untuk membedakan kelas dari antarmuka, penerapan kata kunci hanya diperuntukkan bagi antarmuka.
Anda bisa mengimplementasikan antarmuka apa pun yang Anda suka di kelas yang sama karena mereka tidak memperluas apa pun secara default (tapi Anda bisa membuat antarmuka yang memperluas antarmuka lain, tetapi sekali lagi, antarmuka "ayah" tidak akan memperluas Obyek "), sehingga antarmuka adalah hanya sebuah antarmuka dan mereka tidak akan menderita dari " metode tanda tangan colissions ", jika mereka melakukan compiler akan memberikan peringatan kepada Anda dan Anda hanya perlu mengubah metode tanda tangan untuk memperbaikinya (signature = nama metode + params + jenis kembali) .
public interface Flyer{
public void makeFly(); // <- method without implementation
}
public class Bird extends Abc implements Flyer{
public void doAnotherThing(){
}
@Override
public void makeFly(){ // <- implementation of Flyer interface
}
// Flyer does not have toString() method or any method from class Object,
// no method signature collision will happen here
}
Karena sebuah antarmuka hanyalah kontrak. Dan kelas sebenarnya adalah wadah untuk data.
Misalnya dua kelas A, B memiliki metode yang sama m1 (). Dan kelas C memperpanjang A, B.
class C extends A, B // for explaining purpose.
Sekarang, kelas C akan mencari definisi m1. Pertama, ia akan mencari di kelas jika tidak menemukan maka akan memeriksa ke kelas orang tua. Kedua A, B memiliki definisi Jadi di sini terjadi ambiguitas definisi mana yang harus dipilih. Jadi JAWA TIDAK MENDUKUNG WARISAN GANDA.
Java tidak mendukung multiple inheritance karena dua alasan:
Object
kelas. Ketika mewarisi dari lebih dari satu kelas super, sub kelas mendapatkan ambiguitas untuk mendapatkan properti dari kelas Obyek.super()
untuk memanggil konstruktor kelas perjamuan. Jika kelas memiliki lebih dari satu kelas super, itu jadi bingung.Jadi, ketika satu kelas memanjang dari lebih dari satu kelas super, kami mendapatkan kesalahan waktu kompilasi.
Ambil contoh kasus di mana Kelas A memiliki metode getSomething dan kelas B memiliki metode getSomething dan kelas C meluas A dan B. Apa yang akan terjadi jika seseorang bernama C.getSomething? Tidak ada cara untuk menentukan metode mana yang harus dihubungi.
Antarmuka pada dasarnya hanya menentukan metode apa yang perlu dimiliki oleh kelas pelaksana. Kelas yang mengimplementasikan beberapa antarmuka hanya berarti kelas harus mengimplementasikan metode dari semua antarmuka itu. Whci tidak akan menyebabkan masalah apa pun seperti yang dijelaskan di atas.
Pertimbangkan skenario di mana Test1, Test2 dan Test3 adalah tiga kelas. Kelas Test3 mewarisi kelas Test2 dan Test1. Jika kelas Test1 dan Test2 memiliki metode yang sama dan Anda memanggilnya dari objek kelas anak, akan ada ambiguitas untuk memanggil metode dari kelas Test1 atau Test2 tetapi tidak ada ambiguitas untuk antarmuka seperti di antarmuka tidak ada implementasi di sana.
Java tidak mendukung multiple inheritance, multipath dan hybrid inheritance karena masalah ambiguitas:
Scenario for multiple inheritance: Let us take class A , class B , class C. class A has alphabet(); method , class B has also alphabet(); method. Now class C extends A, B and we are creating object to the subclass i.e., class C , so C ob = new C(); Then if you want call those methods ob.alphabet(); which class method takes ? is class A method or class B method ? So in the JVM level ambiguity problem occurred. Thus Java does not support multiple inheritance.
Tautan Referensi: https://plus.google.com/u/0/communities/102217496457095083679
secara sederhana kita semua tahu, kita dapat mewarisi (memperluas) satu kelas tetapi kita dapat mengimplementasikan begitu banyak antarmuka .. itu karena dalam antarmuka kita tidak memberikan implementasi, katakan saja fungsionalitasnya. misalkan jika java dapat meluas begitu banyak kelas dan mereka memiliki metode yang sama .. pada titik ini jika kita mencoba memanggil metode super kelas di sub kelas metode apa yang seharusnya dijalankan ??, kompiler menjadi bingung contoh: - mencoba beberapa ekstensi tetapi dalam antarmuka metode-metode itu tidak memiliki tubuh kita harus mengimplementasikannya di sub kelas .. coba beberapa alat jadi jangan khawatir ..
* Ini adalah jawaban sederhana karena saya seorang pemula di Jawa *
Anggap ada tiga kelas X
, Y
dan Z
.
Jadi kita mewarisi seperti X extends Y, Z
Dan keduanya Y
dan Z
memiliki metode alphabet()
dengan tipe pengembalian dan argumen yang sama. Metode ini alphabet()
di Y
mengatakan untuk menampilkan alfabet pertama dan alfabet metode di Z
mengatakan menampilkan alfabet terakhir . Jadi inilah ambiguitas ketika alphabet()
dipanggil oleh X
. Apakah itu mengatakan untuk menampilkan alfabet pertama atau terakhir ??? Jadi java tidak mendukung multiple inheritance. Dalam hal Antarmuka, pertimbangkan Y
dan . Jadi tidak ada alasan untuk meningkatkan ambiguitas. Kita dapat mendefinisikan metode dengan apa pun yang kita inginkan di dalam kelas .Z
sebagai antarmuka. Jadi keduanya akan berisi deklarasi metode alphabet()
tetapi bukan definisi. Itu tidak akan memberitahu apakah akan menampilkan alfabet pertama atau alfabet terakhir atau apa pun tetapi hanya akan mendeklarasikan metodealphabet()
X
Jadi singkatnya, dalam definisi Interface dilakukan setelah implementasi sehingga tidak ada kebingungan.