Extendiéndose desde dos clases

150

Cómo puedo hacer esto:

public class Main extends ListActivity , ControlMenu 

Además, me gustaría saber que si este enfoque está bien, hice los menús en clase, que es ControlMenu, y los estoy ampliando en el resto de las actividades.

Umar
fuente
44
No puede extender dos o más clases a la vez. La herencia múltiple no está permitida en Java.
yogsma

Respuestas:

156

Solo puede extender una sola clase. E implementar interfaces de muchas fuentes.

Extender múltiples clases no está disponible. La única solución que se me ocurre es no heredar ninguna de las clases, sino tener una variable interna de cada clase y hacer más de un proxy redirigiendo las solicitudes a su objeto al objeto al que desea que vayan.

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

Esta es la mejor solución que se me ocurrió. Puede obtener la funcionalidad de ambas clases y aún así, en realidad, solo puede ser de un tipo de clase.

El inconveniente es que no puedes encajar en el molde de la clase interna usando un yeso.

El codificador perezoso
fuente
2
fuiste más rápido :)
Dejaré
1
Esta es una alternativa muy buena y proporciona mucha más flexibilidad en el futuro.
David Souther
1
Vea la solución @SCB para obtener una solución más OOP
idish
Podría usar un ejemplo más preciso aquí. No estoy seguro si entiendo.
Neo42
54

¿Por qué no utilizar una clase interna (anidamiento)

class A extends B {
    private class C extends D {
        //Classes A , B , C , D accessible here 
    }
}
Ifte
fuente
44
Enfoque interesante, ¿qué piensan los expertos de esta técnica? Me gustaría profundizar en eso.
TechNyquist
1
¿Está bien con las convenciones?
totten
2
No se pudo lograr que la clase interna trabaje en a Fragment. Mi actividad debe extenderse Fragment, lo que significa que necesito absolutamente getView(), lo que no funcionará si está dentro de la clase interna, y el código allí es donde necesito usar el código ListActivity, por lo que no puedo extender dos veces, O hacer una clase interna en este ejemplo.
Azurespot
Esta es la mejor solución para extender clases abstractas donde necesita acceso a variables de la clase inminente.
tak3shi
45

Como todos los demás han dicho. No puedes. Sin embargo, a pesar de que las personas han dicho muchas veces a lo largo de los años que debería usar múltiples interfaces, realmente no han explicado cómo. Esperemos que esto ayude.

Digamos que sí class Fooy class Barque ambos quieren intentar extenderse a a class FooBar. Por supuesto, como dijiste, no puedes hacer:

public class FooBar extends Foo, Bar

La gente ya ha entrado en las razones de esto hasta cierto punto. En cambio, escriba interfacespara ambos Fooy Barcubra todos sus métodos públicos. P.ej

public interface FooInterface {

    public void methodA();

    public int methodB();

    //...
} 

public interface BarInterface {

    public int methodC(int i);

    //...
}

Y ahora crea Fooe Barimplementa las interfaces relativas:

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

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

Ahora, con class FooBar, se puede implementar tanto FooInterfacey BarInterfacemientras se mantiene una Fooy Barobjeto y de paso los métodos directamente a través de:

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

    //...

}

La ventaja de este método es que el FooBarobjeto se ajusta a los moldes de ambos FooInterfacey BarInterface. Eso significa que esto está perfectamente bien:

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

Espero que esto aclare cómo usar interfaces en lugar de múltiples extensiones. Incluso si llego unos años tarde.

SCB
fuente
66
esta es la mejor respuesta
user3290180
Esta es una muy buena respuesta, sin embargo, veo un par de problemas que deberían abordarse con más detalle. Primero, extenderse desde dos clases existentes sería un poco más problemático y habría que superar varios obstáculos adicionales. Segundo, si la interfaz Foo y Bar tienen las mismas funciones, necesitaría tener un orden de precedencia. Extender explícitamente tu clase te obligaría a tomar esas decisiones por adelantado. Aún así, Excelente opción :) +1
The Lazy Coder
¿Qué sucede si tenemos que crear nuevas clases "con frecuencia" y hacer que cada una de esas clases implemente ambas interfaces? Entonces, tendríamos que repetir estas implementaciones repetitivas en cada clase. ¿Hay una mejor manera de hacer que una clase "implemente" dos conjuntos de comportamientos?
MasterJoe2
1
@ MasterJoe2 Para ser sincero, hace mucho tiempo que no uso Java (me detuve cuando escribí esta respuesta). Una de las razones por las que lo evito hoy en día es el problema que planteas. Una corazonada para una dirección que posiblemente podría investigar, es escribir una clase abstracta que implemente ambas interfaces y ampliarla. Sin embargo, no tengo ni idea de si eso es Java válido, y creo que terminarás con el mismo problema original cuando quieras hacer cambios en la clase de implementación en el futuro. Lo siento, no puedo ser más de ayuda.
SCB
37

Querrás usar interfaces. En general, la herencia múltiple es mala debido al 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 ++ y otros tienen un par de formas de resolver esto, p. Ej.

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

pero Java solo usa interfaces.

Los senderos de Java tienen una excelente introducción a las interfaces: http://download.oracle.com/javase/tutorial/java/concepts/interface.html Probablemente quieras seguir eso antes de sumergirte en los matices de la API de Android.

David Souther
fuente
24
Nunca entendí por qué el problema del diamante es en realidad un problema que impide la herencia múltiple. ¿Por qué el compilador no puede simplemente quejarse si hay métodos en conflicto con el mismo nombre?
pete
1
Para compiladores suficientemente inteligentes, no lo es. Es posible resolverlo en el nivel del compilador, y de hecho C ++ lo hace con virtual class. Hacerlo viene con muchas advertencias y advertencias, tanto para el compilador como para el desarrollador.
David Souther
1
¿Qué tal los mismos métodos predeterminados en dos interfaces? Ese es otro ejemplo del problema del diamante, que Java puede manejar.
Lajos Meszaros
1
@ MészárosLajos Pero no se llama superdesde un método heredado. Bueno, puede, pero debe especificar el método de interfaz para invocar (y debe usar la palabra clave defaulten la implementación de la interfaz) . Un ejemplo es: MyIFace.super.foo()donde MyIFace es una interfaz. Como puede ver, el método de interfaz para ejecutar está definido y evita el problema del diamante por completo. Si extiende MyClass1y MyClass2, ambas clases tienen un foo(), y llama, super.foo()entonces el Compilador es lanzado por el Problema Diamante.
JDSweetBeat
No puede regresar "bar"o "baz"con el tipo de método de void. De todos modos, buena explicación xD
xdevs23
22

Sí, como todos los demás escribieron, no se puede hacer herencia múltiple en Java. Si tiene dos clases de las cuales le gustaría usar el código, normalmente solo subclase una (por ejemplo, clase A). Para la clase B, abstraes los métodos importantes de la misma en una interfaz BInterface(nombre feo, pero entiendes la idea), luego dices Main extends A implements BInterface. En el interior, puede crear una instancia de un objeto de clase Be implementar todos los métodos BInterfacellamando a las funciones correspondientes de B.

Esto cambia la relación "es-a" a una relación "tiene-a" como su Mainahora es un A, pero tiene un B. Dependiendo de su caso de uso, incluso puede hacer que ese cambio sea explícito eliminando el BInterfacede su Aclase y en su lugar proporcionar un método para acceder a su objeto B directamente.

Nicolas78
fuente
Esta es la explicación más legible y fácil de entender. Más votos a favor por favor.
Algorini
6

Java no admite herencia múltiple, pero puede intentar implementar dos o más interfaces.


fuente
4

Si. Slandau tiene razón. Java no permite extender desde varias clases.

Lo que quieres es probablemente public class Main extends ListActivity implements ControlMenu. Supongo que estás tratando de hacer una lista.

Espero que ayude.

torbellino
fuente
3

Como otra alternativa, tal vez pueda usar una interfaz con una implementación predeterminada de un método. Eso depende, por supuesto, de lo que quieras hacer.

Por ejemplo, puede crear una clase abstracta y una interfaz:

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

Entonces, después de eso, puede extender e implementar ambas clases y usar ambos métodos.

public class extends FatherClass implements InterfaceWithDefaultsMethods {

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

Espero que esto te ayude...

huellas dactilares
fuente
2

es posible

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

//blah
}
Jonathan
fuente
Parallaxory ParallaxControllerson desconocidos, así que supongo que no son clases SDK. Entonces esto no funciona para mí (y, por lo tanto, esta respuesta muestra errores). ¿Qué es ParallaxController? ¿Es esta una dependencia específica? Por favor explique
Zoe
1

Los creadores de Java decidieron que los problemas de la herencia múltiple superan los beneficios, por lo que no incluyeron la herencia múltiple. Puede leer sobre uno de los mayores problemas de herencia múltiple (el problema del doble diamante) aquí .

Los dos conceptos más similares son la implementación de la interfaz y la inclusión de objetos de otras clases como miembros de la clase actual. El uso de métodos predeterminados en las interfaces es casi exactamente lo mismo que la herencia múltiple, sin embargo, se considera una mala práctica usar una interfaz solo con métodos predeterminados.

Pika el mago de las ballenas
fuente
0

no puedes hacer herencia múltiple en java. considere usar interfaces:

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

o clases internas:

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

fuente