JavaRush /Java-Blog /Random-DE /Mehrfachvererbung in Java. Zusammensetzung vs. Vererbung
DSergey_Kh
Level 12

Mehrfachvererbung in Java. Zusammensetzung vs. Vererbung

Veröffentlicht in der Gruppe Random-DE

Mehrfachvererbung in Java

Mit der Mehrfachvererbung können Sie eine Klasse erstellen, die von mehreren Superklassen erbt. Im Gegensatz zu einigen anderen gängigen objektorientierten Programmiersprachen wie C++ erlaubt Java keine Mehrfachvererbung von Klassen. Java unterstützt die Vererbung mehrerer Klassen nicht, da dies zum Diamantproblem führen kann. Und anstatt nach Wegen zu suchen, dieses Problem zu lösen, gibt es bessere Möglichkeiten, wie wir das gleiche Ergebnis wie bei der Mehrfachvererbung erzielen können.

Diamantproblem

Um das Diamantproblem besser zu verstehen, nehmen wir an, dass Mehrfachvererbung in Java unterstützt wird. In diesem Fall könnten wir eine Klassenhierarchie haben, wie im Bild unten gezeigt. Mehrfachvererbung in Java.  Zusammensetzung vs. Vererbung – 1Nehmen wir an, dass die Klasse SuperClassabstrakt ist und eine Methode darin deklariert ist. Sowohl konkrete Klassen ClassAals auch ClassB.
package com.journaldev.inheritance;
public abstract class SuperClass {
	public abstract void doSomething();
}
package com.journaldev.inheritance;
public class ClassA extends SuperClass{
	@Override
	public void doSomething(){
		System.out.println("doSomething implementation of A");
	}
	//ClassA own method
	public void methodA(){
	}
}
package com.journaldev.inheritance;
public class ClassB extends SuperClass{
	@Override
	public void doSomething(){
		System.out.println("doSomething implementation of B");
	}
	//ClassB specific method
	public void methodB(){
	}
}
Nehmen wir nun an, wir möchten es implementieren ClassCund von ClassAand erben ClassB.
package com.journaldev.inheritance;
public class ClassC extends ClassA, ClassB{
	public void test(){
		//calling super class method
		doSomething();
	}
}
Beachten Sie, dass die Methode test()die Superklassenmethode aufruft doSomething(). Dies führt zu Mehrdeutigkeiten, da der Compiler nicht weiß, welche Methode der Oberklasse er ausführen soll. Dies ist ein rautenförmiges Klassendiagramm, das als Diamantproblem bezeichnet wird. Dies ist der Hauptgrund, warum Java die Mehrfachvererbung nicht unterstützt. Beachten Sie, dass das obige Problem bei der Vererbung mehrerer Klassen nur bei drei Klassen auftreten kann, die mindestens eine gemeinsame Methode haben.

Vererbung mehrerer Schnittstellen

In Java wird Mehrfachvererbung in Klassen nicht unterstützt, wohl aber in Schnittstellen. Und eine Schnittstelle kann viele andere Schnittstellen erweitern. Unten finden Sie ein einfaches Beispiel.
package com.journaldev.inheritance;
public interface InterfaceA {
	public void doSomething();
}
package com.journaldev.inheritance;
public interface InterfaceB {
	public void doSomething();
}
Beachten Sie, dass beide Schnittstellen dieselbe Methode deklarieren. Jetzt können wir eine Schnittstelle erstellen, die diese beiden Schnittstellen erweitert, wie im folgenden Beispiel gezeigt.
package com.journaldev.inheritance;
public interface InterfaceC extends InterfaceA, InterfaceB {
	//same method is declared in InterfaceA and InterfaceB both
	public void doSomething();
}
Das funktioniert hervorragend, da Schnittstellen nur Methoden deklarieren und die Implementierung in Klassen erfolgt, die die Schnittstelle erben. Daher gibt es keine Möglichkeit, bei der Vererbung mehrerer Schnittstellen Mehrdeutigkeiten zu erzeugen.
package com.journaldev.inheritance;
public class InterfacesImpl implements InterfaceA, InterfaceB, InterfaceC {
	@Override
	public void doSomething() {
		System.out.println("doSomething implementation of concrete class");
	}
	public static void main(String[] args) {
		InterfaceA objA = new InterfacesImpl();
		InterfaceB objB = new InterfacesImpl();
		InterfaceC objC = new InterfacesImpl();

		//all the method calls below are going to same concrete implementation
		objA.doSomething();
		objB.doSomething();
		objC.doSomething();
	}
}
Bitte beachten Sie, dass Sie immer die Annotation verwenden, wenn Sie eine Superklassenmethode überschreiben oder eine Schnittstellenmethode implementieren @Override. methodA()Was ist, wenn wir eine Funktion einer Klasse ClassAund eine Funktion methodB()einer Klasse ClassBin einer Klasse verwenden möchten ClassC? Die Lösung liegt in der Verwendung von Komposition. Nachfolgend finden Sie eine Version der Klasse ClassC, die Komposition verwendet, um sowohl die Klassenmethoden als auch die Methode doSomething()eines der Objekte zu definieren.
package com.journaldev.inheritance;
public class ClassC{
	ClassA objA = new ClassA();
	ClassB objB = new ClassB();
	public void test(){
		objA.doSomething();
	}
	public void methodA(){
		objA.methodA();
	}
	public void methodB(){
		objB.methodB();
	}
}

Zusammensetzung vs. Vererbung

Eine der besten Java-Programmierpraktiken besteht darin, „die Zusammensetzung vor der Vererbung zu genehmigen“. Wir werden einige der Aspekte untersuchen, die diesen Ansatz begünstigen.
  1. Nehmen wir an, wir haben eine Superklasse und eine Klasse, die sie erweitert:

    package com.journaldev.inheritance;
    public class ClassC{
    	public void methodC(){
    	}
    }
    package com.journaldev.inheritance;
    public class ClassD extends ClassC{
    	public int test(){
    		return 0;
    	}
    }

    Der obige Code lässt sich kompilieren und funktioniert gut. Was aber, wenn wir die Implementierung der Klasse ClassCwie unten gezeigt ändern:

    package com.journaldev.inheritance;
    public class ClassC{
    	public void methodC(){
    	}
    	public void test(){
    	}
    }

    Beachten Sie, dass die Methode test()bereits in der Unterklasse vorhanden ist, der Rückgabetyp jedoch unterschiedlich ist. Jetzt wird die Klasse ClassDnicht kompiliert und wenn Sie eine IDE verwenden, werden Sie aufgefordert, den Rückgabetyp in der Oberklasse oder Unterklasse zu ändern.

    Stellen Sie sich nun eine Situation vor, in der wir eine mehrstufige Klassenvererbungshierarchie haben und keinen Zugriff auf die Oberklasse haben. Wir haben keine andere Wahl, als die Signatur unserer Unterklassenmethode oder ihren Namen zu ändern, um den Kompilierungsfehler zu beheben. Wir müssen auch die Unterklassenmethode an allen Stellen ändern, an denen sie aufgerufen wird. Daher macht die Vererbung unseren Code spröde.

    Das oben genannte Problem wird bei der Komposition nie auftreten und dies macht sie für die Vererbung attraktiver.

  2. Ein weiteres Problem bei der Vererbung besteht darin, dass wir dem Client alle Methoden der Superklasse zur Verfügung stellen. Wenn unsere Superklasse nicht richtig entworfen ist und Sicherheitslücken bestehen, sind wir von der schlechten Implementierung betroffen, obwohl wir die beste Implementierung unserer Klasse implementieren der Oberklasse. Die Komposition hilft uns bei der Bereitstellung eines kontrollierten Zugriffs auf Methoden der Oberklasse, während die Vererbung keine Kontrolle über Methoden der Oberklasse bietet. Dies ist auch einer der Hauptvorteile der Komposition aus Vererbung.

  3. Ein weiterer Vorteil der Komposition besteht darin, dass sie Flexibilität beim Aufrufen von Methoden ermöglicht. Unsere Implementierung der ClassCoben dargestellten Klasse ist nicht optimal und stellt sicher, dass die Kompilierungszeit an die aufzurufende Methode gebunden ist. Mit minimalen Änderungen können wir den Methodenaufruf flexibel und dynamisch gestalten.

    package com.journaldev.inheritance;
    public class ClassC{
    	SuperClass obj = null;
    	public ClassC(SuperClass o){
    		this.obj = o;
    	}
    	public void test(){
    		obj.doSomething();
    	}
    	public static void main(String args[]){
    		ClassC obj1 = new ClassC(new ClassA());
    		ClassC obj2 = new ClassC(new ClassB());
    
    		obj1.test();
    		obj2.test();
    	}
    }

    Das Ergebnis des oben vorgestellten Programms:

    doSomething implementation of A
    doSomething implementation of B

    Diese Flexibilität beim Methodenaufruf ist bei der Vererbung nicht verfügbar, was einen weiteren Vorteil für die Kompositionsauswahl darstellt.

  4. Unit-Tests lassen sich mit der Komposition einfacher durchführen, da wir wissen, dass wir alle Methoden aus der Oberklasse verwenden und sie für den Test kopieren können. Bei der Vererbung hingegen sind wir stärker von der Oberklasse abhängig und kennen nicht alle Methoden der Oberklasse, die verwendet werden. Wir müssen also alle Methoden der Oberklasse testen, was aufgrund der Vererbung einen Mehraufwand bedeutet.

    Im Idealfall sollten wir die Vererbung nur verwenden, wenn die Beziehung zwischen Unterklasse und Oberklasse als „ist“ definiert ist. In allen anderen Fällen wird die Verwendung der Zusammensetzung empfohlen.

Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION