Si estende da due classi


150

Come posso fare questo:

public class Main extends ListActivity , ControlMenu 

Inoltre, vorrei sapere che questo approccio va bene per il fatto che ho creato i menu in classe che è ControlMenu e che sto estendendo nel resto delle attività.


4
Non è possibile estendere due o più classi contemporaneamente. L'ereditarietà multipla non è consentita in Java.
Yogsma,

Risposte:


156

Puoi estendere solo una singola classe. E implementare interfacce da molte fonti.

L'estensione di più classi non è disponibile. L'unica soluzione a cui riesco a pensare non è ereditare nessuna delle due classi ma avere invece una variabile interna di ciascuna classe e fare più di un proxy reindirizzando le richieste al tuo oggetto sull'oggetto a cui vuoi che vadano.

 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();
     }
 }

questa è la soluzione migliore che ho trovato. Puoi ottenere la funzionalità da entrambe le classi e in realtà è ancora solo di un tipo di classe.

Lo svantaggio è che non puoi inserirti nello stampo della classe interna usando un cast.


2
sei stato più veloce :) Lascerò la mia risposta come un astratto vagabondo da confrontare con il tuo esempio concreto;)
Nicolas78

1
Questa è un'ottima alternativa e offre molta più flessibilità in futuro.
David Souther,

1
Vedi la soluzione @SCB per ulteriori soluzioni OOP
idish

Potrei usare un esempio più preciso qui. Non sono sicuro di aver capito.
Neo42,

54

Perché non usare una classe interna (Nesting)

class A extends B {
    private class C extends D {
        //Classes A , B , C , D accessible here 
    }
}

4
Approccio interessante, cosa ne pensano gli esperti di questa tecnica? Mi piacerebbe scavarci dentro.
TechNyquist,

1
Va bene con le convenzioni?
ottenuto il

2
Impossibile far funzionare la classe interna in a Fragment. La mia attività deve estendersi Fragment, il che significa che ne ho assolutamente bisogno getView(), che non funzionerà se è all'interno della classe interna, e il codice lì dentro è dove devo usare il codice ListActivity, quindi non posso estenderlo due volte, O fare una classe interna in questo esempio.
Azurespot

Questa è la soluzione migliore per estendere le classi astratte in cui è necessario accedere alle variabili della classe di implementazione.
tak3shi,

45

Come hanno detto tutti gli altri. No, non puoi. Tuttavia, anche se nel corso degli anni le persone hanno affermato che dovresti usare più interfacce, non hanno ancora capito come. Spero che questo possa aiutare.

Di 'che hai class Fooe class Barche entrambi vuoi provare ad estenderti in a class FooBar. Naturalmente, come hai detto, non puoi fare:

public class FooBar extends Foo, Bar

Le persone hanno già approfondito le ragioni di ciò. Invece, scrivi interfacesper entrambi Fooe Barcopre tutti i loro metodi pubblici. Per esempio

public interface FooInterface {

    public void methodA();

    public int methodB();

    //...
} 

public interface BarInterface {

    public int methodC(int i);

    //...
}

E ora crea Fooe Barimplementa le relative interfacce:

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

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

Ora, con class FooBar, è possibile implementare entrambiFooInterface e BarInterfacemantenendo un Fooe Baroggetto e passando semplicemente i metodi attraverso:

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);
    }

    //...

}

Il vantaggio di questo metodo è che FooBar oggetto si adatta agli stampi di entrambi FooInterfacee BarInterface. Ciò significa che va benissimo:

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);

Spero che questo chiarisca come utilizzare le interfacce anziché più estensioni. Anche se sono in ritardo di qualche anno.


6
questa è la risposta migliore
user3290180,

Questa è un'ottima risposta, tuttavia vedo un paio di problemi che dovrebbero essere affrontati in modo più dettagliato. La prima estensione da due classi esistenti sarebbe un po 'più problematica e ci sarebbero un certo numero di ostacoli extra da percorrere, in secondo luogo se l'interfaccia Foo e Bar avessero entrambe le stesse funzioni, avresti bisogno di avere un ordine di precedenza. L'estensione esplicita della tua classe ti costringerebbe a prendere quelle decisioni in anticipo. Ancora, Opzione eccellente :) +1
The Lazy Coder

E se dovessimo creare nuove classi "frequentemente" e far sì che ognuna di queste classi implementasse entrambe le interfacce? Quindi, dovremmo ripetere queste implementazioni del plateplate in ogni classe. Esiste un modo migliore per fare in modo che una classe "attui" due serie di comportamenti?
MasterJoe2,

1
@ MasterJoe2 Ad essere sincero, non uso molto Java da un po 'di tempo (mi sono fermato quando ho scritto questa risposta). Uno dei motivi per cui lo evito oggi è il problema che sollevi. Un sospetto per una direzione che potresti eventualmente indagare, sta scrivendo una classe astratta che implementa entrambe le interfacce e la estende. Tuttavia, non ho idea se si tratti di Java valido e ritengo che alla fine si verificherà lo stesso problema originale quando si desidera apportare modifiche alla classe di implementazione. Mi dispiace, non posso essere più di aiuto.
SCB,

37

Ti consigliamo di utilizzare le interfacce. In genere, l'ereditarietà multipla è negativa a causa del problema del diamante:

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 ++ e altri hanno un paio di modi per risolvere questo problema, ad es

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

ma Java utilizza solo interfacce.

I Java Trails hanno una grande introduzione sulle interfacce: http://download.oracle.com/javase/tutorial/java/concepts/interface.html Probabilmente vorrai seguirlo prima di immergerti nelle sfumature dell'API di Android.


24
Non ho mai capito perché il problema del diamante sia in realtà un problema che impedisce l'ereditarietà multipla. Perché il compilatore non può semplicemente lamentarsi se esistono metodi in conflitto con lo stesso nome?
pete,

1
Per compilatori sufficientemente intelligenti, non lo è. Risolverlo a livello di compilatore è possibile, e in effetti C ++ lo fa virtual class. Ciò comporta molti avvertimenti e avvertenze, sia per il compilatore che per lo sviluppatore.
David Souther,

1
Che ne dici degli stessi metodi predefiniti in due interfacce? Questo è un altro esempio del problema del diamante, che Java può gestire.
Lajos Meszaros,

1
@ MészárosLajos Ma non si chiama superda un metodo che eredita. Bene, puoi, ma devi specificare il metodo di interfaccia da invocare (e deve usare la parola chiave defaultnell'implementazione dell'interfaccia) . Un esempio è: MyIFace.super.foo()dove MyIFace è un'interfaccia. Come puoi vedere, il metodo di interfaccia da eseguire è definito ed evita del tutto il problema del diamante. Se estendi MyClass1e MyClass2, entrambe le classi hanno un foo(), e call, super.foo()il compilatore viene lanciato dal problema del diamante.
JDSweetBeat,

Non è possibile restituire "bar"o "baz"con il tipo di metodo di void. Comunque, buona spiegazione xD
xdevs23

22

Sì, come hanno scritto tutti gli altri, non è possibile eseguire l'ereditarietà multipla in Java. Se hai due classi da cui desideri utilizzare il codice, in genere ne devi solo una sottoclasse (ad esempio classe A). Per la classe B, astratti i metodi importanti di esso su un'interfaccia BInterface(brutto nome, ma ottieni l'idea), quindi dici Main extends A implements BInterface. All'interno, è possibile creare un'istanza di un oggetto di classe Be implementare tutti i metodi BInterfacechiamando le corrispondenti funzioni diB .

Questo cambia la relazione "is-a" in una relazione "has-a" come Mainora è una A, ma ha una B. A seconda del tuo caso d'uso, potresti persino rendere esplicito quel cambiamento rimuovendo BInterfacedalla tua Aclasse e invece fornire un metodo per accedere direttamente al tuo oggetto B.


Questa è la spiegazione più leggibile e di facile comprensione. Più voti per favore.
Algorini,


6

Java non supporta l'ereditarietà multipla, ma puoi provare a implementare due o più interfacce.


4

Sì. Slandau ha ragione. Java non consente l'estensione da più classi.

Quello che vuoi è probabilmente public class Main extends ListActivity implements ControlMenu . Immagino che tu stia cercando di fare un elenco.

Spero che aiuti.


3

Come un'altra alternativa, forse puoi usare un'interfaccia con un'implementazione predefinita di un metodo. Dipende ovviamente da quello che vuoi fare.

Ad esempio, puoi creare una classe astratta e un'interfaccia:

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.
    }
}

Quindi, in seguito, è possibile estendere e implementare entrambe le classi e utilizzare entrambi i metodi.

public class extends FatherClass implements InterfaceWithDefaultsMethods {

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

Spero che questo ti aiuti ...



2

è possibile

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

//blah
}

Parallaxore ParallaxControllersono sconosciuti, quindi presumo che non siano classi SDK. Quindi questo non funziona per me (e quindi questa risposta mostra errori). Che cos'è ParallaxController? È una dipendenza specifica? Si prega di elaborare
Zoe,

1

I creatori di Java hanno deciso che i problemi dell'ereditarietà multipla superano i benefici, quindi non hanno incluso l'ereditarietà multipla. Puoi leggere uno dei più grandi problemi di eredità multipla (il problema del doppio diamante) qui .

I due concetti più simili sono l'implementazione dell'interfaccia e includono oggetti di altre classi come membri della classe corrente. L'uso di metodi predefiniti nelle interfacce è quasi identico a quello dell'ereditarietà multipla, tuttavia è considerato una pratica errata utilizzare un'interfaccia con solo metodi predefiniti.


0

non puoi fare l'ereditarietà multipla in java. considerare l'utilizzo di interfacce:

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

o classi interne:

class Outer {
    class Inner1 extends Class1 {}
    class Inner2 extends Class2 {}
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.