Erweiterung von zwei Klassen

150

Wie kann ich das machen:

public class Main extends ListActivity , ControlMenu 

Außerdem würde ich gerne wissen, dass dieser Ansatz in Ordnung ist, dass ich die Menüs in der Klasse ControlMenu erstellt habe und sie in den restlichen Aktivitäten erweitere.

umar
quelle
4
Sie können nicht zwei oder mehr Klassen gleichzeitig verlängern. Mehrfachvererbung ist in Java nicht zulässig.
Yogasma

Antworten:

156

Sie können nur eine einzelne Klasse erweitern. Und implementieren Sie Schnittstellen aus vielen Quellen.

Das Erweitern mehrerer Klassen ist nicht verfügbar. Die einzige Lösung, die ich mir vorstellen kann, besteht darin, keine der beiden Klassen zu erben, sondern stattdessen eine interne Variable jeder Klasse zu haben und mehr als Proxy zu fungieren, indem die Anforderungen an Ihr Objekt an das Objekt umgeleitet werden, zu dem sie gehen sollen.

 public class CustomActivity extends Activity {

     private AnotherClass mClass;

     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         mClass = new AnotherClass(this);
     }

     //Implement each method you want to use.
     public String getInfoFromOtherClass()
     {
        return mClass.getInfoFromOtherClass();
     }
 }

Dies ist die beste Lösung, die ich mir ausgedacht habe. Sie können die Funktionalität von beiden Klassen erhalten und dennoch nur von einem Klassentyp sein.

Der Nachteil ist, dass Sie nicht mit einem Guss in die Form der internen Klasse passen können.

Der faule Codierer
quelle
2
du warst schneller :) Ich werde meine Antwort als eine abstrakte Wanderung hinterlassen, um sie mit deinem konkreten Beispiel zu vergleichen;)
Nicolas78
1
Dies ist eine sehr schöne Alternative und bietet in Zukunft viel mehr Flexibilität.
David Souther
1
Siehe @SCB-Lösung für mehr eine OOP-Lösung
idish
Ich könnte hier ein genaueres Beispiel verwenden. Nicht sicher ob ich verstehe.
Neo42
54

Warum nicht eine innere Klasse verwenden (Verschachtelung)

class A extends B {
    private class C extends D {
        //Classes A , B , C , D accessible here 
    }
}
Ifte
quelle
4
Interessanter Ansatz, was halten Experten von dieser Technik? Ich würde gerne darin graben.
TechNyquist
1
Ist es in Ordnung mit Konventionen?
Totten
2
Konnte die innere Klasse nicht dazu bringen, in einem zu arbeiten Fragment. Meine Aktivität muss erweitert werden Fragment, was bedeutet, dass ich unbedingt etwas brauche getView(), was nicht funktioniert, wenn es sich innerhalb der inneren Klasse befindet, und der Code dort ist der Ort, an dem ich Code verwenden muss ListActivity, sodass ich nicht zweimal erweitern oder eine innere Klasse erstellen kann in diesem Beispiel.
Azurespot
Dies ist die beste Lösung zum Erweitern von abstrakten Klassen, bei denen Sie Zugriff auf Variablen der implementierenden Klasse benötigen.
Tak3shi
45

Wie alle anderen gesagt haben. Nein, das kannst du nicht. Obwohl die Leute im Laufe der Jahre oft gesagt haben, dass Sie mehrere Schnittstellen verwenden sollten, haben sie sich nicht wirklich damit befasst, wie. Hoffentlich hilft das.

Angenommen, Sie haben class Foound class Barmöchten beide versuchen, sich in eine zu erweitern class FooBar. Natürlich können Sie, wie Sie sagten, nicht Folgendes tun:

public class FooBar extends Foo, Bar

Die Gründe dafür sind bereits teilweise bekannt. Schreiben Sie stattdessen interfacesfür beide Foound Bardecken Sie alle öffentlichen Methoden ab. Z.B

public interface FooInterface {

    public void methodA();

    public int methodB();

    //...
} 

public interface BarInterface {

    public int methodC(int i);

    //...
}

Und jetzt machen Foound Barimplementieren Sie die relativen Schnittstellen:

public class Foo implements FooInterface { /*...*/ }

public class Bar implements BarInterface { /*...*/ }

Mit class FooBarkönnen Sie jetzt beides implementieren FooInterfaceund BarInterfacedabei ein Foound Bar-Orth behalten und die Methoden direkt durchlaufen:

public class FooBar implements FooInterface, BarInterface {

    Foo myFoo;
    Bar myBar;

    // You can have the FooBar constructor require the arguments for both
    //  the Foo and the Bar constructors
    public FooBar(int x, int y, int z){
        myFoo = new Foo(x);
        myBar = new Bar(y, z);
    }

    // Or have the Foo and Bar objects passed right in
    public FooBar(Foo newFoo, Bar newBar){
        myFoo = newFoo;
        myBar = newBar;
    }

    public void methodA(){
        myFoo.methodA();
    }

    public int methodB(){
        return myFoo.methodB();
    }

    public int methodC(int i){
        return myBar.methodC(i);
    }

    //...

}

Der Bonus für diese Methode ist, dass das FooBarObjekt in die Formen von beiden FooInterfaceund passt BarInterface. Das heißt, das ist vollkommen in Ordnung:

FooInterface testFoo;
testFoo = new FooBar(a, b, c);
testFoo = new Foo(a);

BarInterface testBar;
testBar = new FooBar(a, b, c);
testBar = new Bar(b, c);

Ich hoffe, dies verdeutlicht die Verwendung von Schnittstellen anstelle mehrerer Erweiterungen. Auch wenn ich ein paar Jahre zu spät bin.

SCB
quelle
6
Dies ist die beste Antwort
user3290180
Dies ist eine sehr gute Antwort, ich sehe jedoch einige Probleme, die genauer behandelt werden müssten. Erstens wäre die Erweiterung von zwei vorhandenen Klassen etwas problematischer und es wären einige zusätzliche Hürden zu überwinden. Zweitens: Wenn die Schnittstellen Foo und Bar beide die gleichen Funktionen hätten, müssten Sie eine Rangfolge haben. Eine explizite Erweiterung Ihrer Klasse würde Sie zwingen, diese Entscheidungen im Voraus zu treffen. Trotzdem, ausgezeichnete Option :) +1
The Lazy Coder
Was ist, wenn wir "häufig" neue Klassen erstellen und jede dieser Klassen beide Schnittstellen implementieren lassen müssen? Dann müssten wir diese Boilerplate-Implementierungen in jeder Klasse wiederholen. Gibt es eine bessere Möglichkeit, eine Klasse zwei Verhaltensweisen "implementieren" zu lassen?
MasterJoe2
1
@ MasterJoe2 Um ehrlich zu sein, habe ich seit einiger Zeit nicht mehr viel mit Java gemacht (ich habe ungefähr zu der Zeit aufgehört, als ich diese Antwort geschrieben habe). Einer der Gründe, warum ich es heutzutage vermeide, ist genau das Problem, das Sie ansprechen. Eine Vermutung für eine Richtung, die Sie möglicherweise untersuchen könnten, besteht darin, eine abstrakte Klasse zu schreiben, die beide Schnittstellen implementiert und diese erweitert. Ich habe jedoch keine Ahnung, ob dies gültiges Java ist, und ich habe das Gefühl, dass Sie nur das gleiche ursprüngliche Problem haben werden, wenn Sie in Zukunft Änderungen an der implementierenden Klasse vornehmen möchten. Entschuldigung, ich kann keine größere Hilfe sein.
SCB
37

Sie möchten Schnittstellen verwenden. Im Allgemeinen ist die Mehrfachvererbung aufgrund des Diamantproblems schlecht:

abstract class A {
 abstract string foo();
}

class B extends A {
 string foo () { return "bar"; }
}

class C extends A  {
 string foo() {return "baz"; }
}

class D extends B, C {
 string foo() { return super.foo(); } //What do I do? Which method should I call?
}

C ++ und andere haben einige Möglichkeiten, dies zu lösen, z

string foo() { return B::foo(); }

Java verwendet jedoch nur Schnittstellen.

Die Java-Trails bieten eine großartige Einführung in die Benutzeroberfläche: http://download.oracle.com/javase/tutorial/java/concepts/interface.html Sie sollten dies wahrscheinlich befolgen, bevor Sie sich mit den Nuancen in der Android-API befassen.

David Souther
quelle
24
Ich habe nie verstanden, warum das Diamantproblem tatsächlich ein Problem ist, das Mehrfachvererbung verhindert. Warum kann sich der Compiler nicht einfach beschweren, wenn es widersprüchliche Methoden mit demselben Namen gibt?
Pete
1
Für ausreichend intelligente Compiler ist dies nicht der Fall. Das Lösen auf Compilerebene ist möglich, und C ++ macht es tatsächlich mit virtual class. Dies bringt viele Warnungen und Vorbehalte mit sich, sowohl für den Compiler als auch für den Entwickler.
David Souther
1
Wie wäre es mit den gleichen Standardmethoden in zwei Schnittstellen? Dies ist ein weiteres Beispiel für das Diamantproblem, mit dem Java umgehen kann.
Lajos Meszaros
1
@ MészárosLajos Aber Sie rufen nicht superin einer Methode auf, die erbt. Nun, Sie können, aber Sie müssen die aufzurufende Schnittstellenmethode angeben (und das Schlüsselwort defaultin der Schnittstellenimplementierung verwenden) . Ein Beispiel ist: MyIFace.super.foo()wobei MyIFace eine Schnittstelle ist. Wie Sie sehen, ist die auszuführende Schnittstellenmethode definiert und vermeidet das Diamond-Problem vollständig. Wenn Sie MyClass1und erweitern MyClass2, haben beide Klassen ein foo(), und rufen auf, super.foo()dann wird der Compiler vom Diamond-Problem ausgelöst.
JDSweetBeat
Sie können nicht "bar"oder "baz"mit Methodentyp von zurückgeben void. Wie auch immer, gute Erklärung xD
xdevs23
22

Ja, wie alle anderen geschrieben haben, können Sie in Java keine Mehrfachvererbung durchführen. Wenn Sie zwei Klassen haben, aus denen Sie Code verwenden möchten, unterteilen Sie normalerweise nur eine (z. B. Klasse A). Für den Unterricht Babstrahieren Sie die wichtigen Methoden zu einer Schnittstelle BInterface(hässlicher Name, aber Sie bekommen die Idee) und sagen dann Main extends A implements BInterface. Im Inneren können Sie ein Objekt der Klasse instanziieren Bund alle Methoden von implementieren, BInterfaceindem Sie die entsprechenden Funktionen von aufrufen B.

Dies ändert die "is-a" -Beziehung in eine "has-a" -Beziehung, da Ihre Mainjetzt eine ist A, aber eine hat B. Abhängig von Ihrem Anwendungsfall können Sie diese Änderung sogar explizit vornehmen, indem Sie die BInterfaceaus Ihrer AKlasse entfernen und stattdessen eine Methode bereitstellen, um direkt auf Ihr B-Objekt zuzugreifen.

Nicolas78
quelle
Dies ist die am besten lesbare und leicht verständliche Erklärung. Weitere Upvotes bitte.
Algorini
12

Machen Sie eine Schnittstelle. Java hat keine Mehrfachvererbung.

http://csis.pace.edu/~bergin/patterns/multipleinheritance.html

slandau
quelle
9
aww warum das downvote? Ich war nicht gemein, ich denke nur, er könnte es sich leisten, etwas zu lesen und zuerst selbst über das Problem nachzudenken, bevor wir seine Klassen für ihn
aufbauen
6

Java unterstützt keine Mehrfachvererbung, Sie können jedoch versuchen, zwei oder mehr Schnittstellen zu implementieren.


quelle
4

Ja. Slandau ist richtig. Java erlaubt keine Erweiterung von mehreren Klassen.

Was Sie wollen, ist wahrscheinlich public class Main extends ListActivity implements ControlMenu. Ich vermute, Sie versuchen, eine Liste zu erstellen.

Hoffentlich hilft das.

Wirbel
quelle
3

Wie bei einer anderen Alternative können Sie möglicherweise eine Schnittstelle mit einer Standardimplementierung einer Methode verwenden. Das hängt natürlich davon ab, was Sie tun möchten.

Sie können beispielsweise eine abstrakte Klasse und eine Schnittstelle erstellen:

public abstract class FatherClass {

    abstract void methodInherit() {
        //... do something
    }
}

public interface InterfaceWithDefaultsMethods {
    default void anotherMethod() {
        //... do something
        //... maybe a method with a callable for call another function.
    }
}

Danach können Sie beide Klassen erweitern und implementieren und beide Methoden verwenden.

public class extends FatherClass implements InterfaceWithDefaultsMethods {

    void methode() {
        methodInherit();
        anotherMethod();
    }
}

Hoffe das hilft dir ...

Fingerabdrücke
quelle
2

Das Erweitern von mehreren Klassen ist in Java nicht erlaubt. Um den tödlichen Diamanten des Todes zu verhindern !

akkig
quelle
2

es ist möglich

public class ParallaxViewController<T extends View & Parallaxor> extends ParallaxController<T> implements AbsListView.OnScrollListener {

//blah
}
Jonathan
quelle
Parallaxorund ParallaxControllersind unbekannt, also nehme ich an, dass sie keine SDK-Klassen sind. Das funktioniert bei mir also nicht (und daher zeigt diese Antwort Fehler). Was ist ParallaxController? Ist das eine spezifische Abhängigkeit? Bitte erläutern Sie
Zoe
1

Die Entwickler von Java entschieden, dass die Probleme der Mehrfachvererbung die Vorteile überwiegen, sodass sie die Mehrfachvererbung nicht beinhalteten. Sie können über eine der größten Fragen der Mehrfachvererbung (das doppelte Diamant - Problem) lesen Sie hier .

Die beiden ähnlichsten Konzepte sind die Schnittstellenimplementierung und das Einschließen von Objekten anderer Klassen als Mitglieder der aktuellen Klasse. Die Verwendung von Standardmethoden in Schnittstellen entspricht fast genau der Mehrfachvererbung. Es wird jedoch als schlechte Praxis angesehen, eine Schnittstelle nur mit Standardmethoden zu verwenden.

Pika der Zauberer der Wale
quelle
0

Sie können in Java keine Mehrfachvererbung durchführen. Erwägen Sie die Verwendung von Schnittstellen:

interface I1 {}
interface I2 {}
class C implements I1, I2 {}

oder innere Klassen:

class Outer {
    class Inner1 extends Class1 {}
    class Inner2 extends Class2 {}
}

quelle