java oop inheritance interface language-design

¿Por qué no hay herencia múltiple en Java, pero está permitido implementar múltiples interfaces?



inheritance oop (13)

Java no permite herencia múltiple, pero permite implementar múltiples interfaces. ¿Por qué?


Debido a que la herencia se usa en exceso incluso cuando no se puede decir "hey, ese método parece útil, extenderé esa clase también".

public class MyGodClass extends AppDomainObject, HttpServlet, MouseAdapter, AbstractTableModel, AbstractListModel, AbstractList, AbstractMap, ...


La implementación de múltiples interfaces es muy útil y no causa muchos problemas a los implementadores de lenguaje ni a los programadores. Entonces está permitido. La herencia múltiple, aunque también es útil, puede causar serios problemas a los usuarios (temido diamante de la muerte ). Y la mayoría de las cosas que haces con herencia múltiple también pueden hacerse por composición o usando clases internas. Así que la herencia múltiple está prohibida ya que trae más problemas que ganancias.


Por la misma razón, C # no permite la herencia múltiple pero le permite implementar múltiples interfaces.

La lección aprendida de C ++ con herencias múltiples fue que dio lugar a más problemas de los que valía.

Una interfaz es un contrato de cosas que su clase debe implementar. No obtienes ninguna funcionalidad de la interfaz. La herencia le permite heredar la funcionalidad de una clase principal (y en herencia múltiple, que puede ser extremadamente confusa).

Permitir interfaces múltiples le permite utilizar Patrones de diseño (como Adapter) para resolver los mismos tipos de problemas que puede resolver usando heredadas múltiples, pero de una manera mucho más confiable y predecible.


Porque las interfaces solo especifican qué está haciendo la clase, no cómo lo está haciendo.

El problema con la herencia múltiple es que dos clases pueden definir diferentes formas de hacer lo mismo, y la subclase no puede elegir cuál elegir.


Porque una interfaz es solo un contrato. Y una clase es en realidad un contenedor de datos.


Uno de mis instructores universitarios me lo explicó de esta manera:

Supongamos que tengo una clase, que es una tostadora, y otra clase, que es NuclearBomb. Ambos podrían tener una configuración de "oscuridad". Ambos tienen un método on (). (Uno tiene un apagado (), el otro no). Si quiero crear una clase que sea una subclase de ambos ... como pueden ver, este es un problema que realmente podría explotar en mi cara aquí. .

Por lo tanto, uno de los principales problemas es que si tiene dos clases principales, pueden tener diferentes implementaciones de la misma función, o posiblemente dos funciones diferentes con el mismo nombre, como en el ejemplo de mi instructor. Entonces debes lidiar con decidir cuál va a usar tu subclase. Hay formas de manejar esto, sin duda, C ++ lo hace, pero los diseñadores de Java sintieron que esto haría las cosas demasiado complicadas.

Sin embargo, con una interfaz, estás describiendo algo que la clase es capaz de hacer, en lugar de tomar prestado el método de otra clase para hacer algo. Es mucho menos probable que las interfaces múltiples causen conflictos complejos que deben resolverse que las clases principales múltiples.


Tomemos, por ejemplo, el caso en que la clase A tiene un método getSomething y la clase B tiene un método getSomething y la clase C amplía A y B. ¿Qué pasaría si alguien llamara C.getSomething? No hay forma de determinar qué método llamar.

Las interfaces básicamente solo especifican qué métodos debe contener una clase implementadora. Una clase que implementa múltiples interfaces solo significa que la clase tiene que implementar los métodos desde todas esas interfaces. Lo que no conduciría a ningún problema como se describe anteriormente.



Considere un escenario donde Test1, Test2 y Test3 son tres clases. La clase Test3 hereda las clases Test2 y Test1. Si las clases Test1 y Test2 tienen el mismo método y lo llaman desde un objeto clase infantil, habrá una ambigüedad para llamar al método de la clase Test1 o Test2, pero no existe tal ambigüedad para la interfaz, ya que en la interfaz no hay implementación.


Como este tema no está cerca, publicaré esta respuesta, espero que esto ayude a alguien a entender por qué Java no permite la herencia múltiple.

Considera la siguiente clase:

public class Abc{ public void doSomething(){ } }

En este caso, la clase Abc no se extiende nada, ¿verdad? No tan rápido, esta clase implícita amplía la clase Object, clase base que permite que todo funcione en java. Todo es un objeto

Si intenta utilizar la clase anterior, verá que su IDE le permite usar métodos como: equals(Object o) , toString() , etc., pero no declaró esos métodos, vinieron de la clase base Object

Tu podrías intentar:

public class Abc extends String{ public void doSomething(){ } }

Esto está bien, porque tu clase no extenderá implícitamente el Object sino que ampliará la String porque tú lo dijiste. Considere el siguiente cambio:

public class Abc{ public void doSomething(){ } @Override public String toString(){ return "hello"; } }

Ahora su clase siempre devolverá "hola" si llama a String ().

Ahora imagine la siguiente clase:

public class Flyer{ public void makeFly(){ } } public class Bird extends Abc, Flyer{ public void doAnotherThing(){ } }

De nuevo, la clase Flyer implícita extends Object que tiene el método toString() , cualquier clase tendrá este método, ya que todos extienden Object indirectamente, entonces, si llamas toString() desde Bird , ¿qué toString() tendría que usar? Desde Abc o Flyer ? Esto sucederá con cualquier clase que intente extender dos o más clases, para evitar este tipo de "colisión de método" construyeron la idea de la interfaz , básicamente se podría pensar que es una clase abstracta que no extiende el objeto indirectamente . Como son abstractos , tendrán que ser implementados por una clase, que es un objeto (no se puede instanciar una interfaz solo, deben ser implementados por una clase), por lo que todo seguirá funcionando bien.

Para diferenciar las clases de las interfaces, la palabra clave implements se reservó solo para las interfaces.

Puede implementar cualquier interfaz que desee en la misma clase, ya que no amplía nada por defecto (pero podría crear una interfaz que amplíe otra interfaz, pero una vez más, la interfaz "padre" no extendería Object "), por lo que una interfaz es solo una interfaz y no sufrirán de " colisiones de firmas de métodos ", si lo hacen, el compilador te lanzará una advertencia y solo tendrás que cambiar la firma del método para arreglarlo (signature = nombre del método + params + tipo de retorno) .

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 }


Java admite herencia múltiple a través de interfaces solamente. Una clase puede implementar cualquier cantidad de interfaces pero puede extender solo una clase.

La herencia múltiple no es compatible porque conduce a un problema mortal de diamantes. Sin embargo, puede resolverse pero conduce a un sistema complejo, por lo que los fundadores de Java han descartado la herencia múltiple.

En un libro blanco titulado "Java: una visión general" por James Gosling en febrero de 1995 ( enlace ) da una idea de por qué la herencia múltiple no es compatible con Java.

De acuerdo con Gosling:

"JAVA omite muchas características poco utilizadas, poco entendidas y confusas de C ++ que en nuestra experiencia traen más dolor que bene fi cio. Consiste principalmente en la sobrecarga del operador (aunque tiene sobrecarga de métodos), herencia múltiple y extensas coerciones automáticas".


Java no admite herencia múltiple, multitrayecto e herencia híbrida debido a un problema de ambigüedad:

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.

herencia múltiple

Enlace de referencia: https://plus.google.com/u/0/communities/102217496457095083679


Puede encontrar una respuesta precisa para esta consulta en la página de documentación de Oracle sobre herencia múltiple

  1. Herencia múltiple de estado: posibilidad de heredar campos de múltiples clases

    Una razón por la cual el lenguaje de programación Java no le permite extender más de una clase es evitar los problemas de la herencia múltiple de estado, que es la capacidad de heredar campos de múltiples clases

    Si se permite la herencia múltiple y cuando se crea un objeto instanciando esa clase, ese objeto heredará campos de todas las superclases de la clase. Causará dos problemas.

    1. ¿Qué sucede si los métodos o constructores de diferentes súper clases instancian el mismo campo?
    2. ¿Qué método o constructor tendrá prioridad?
  2. Herencia múltiple de implementación: posibilidad de heredar definiciones de métodos de múltiples clases

    Problemas con este enfoque: nombre conflictos ts y ambigüedad . Si una subclase y una superclase contienen el mismo nombre de método (y firma), el compilador no puede determinar qué versión invocar.

    Pero java admite este tipo de herencia múltiple con métodos predeterminados , que se han introducido desde la versión de Java 8. El compilador de Java proporciona algunas reglas para determinar qué método predeterminado usa una clase en particular.

    Consulte la publicación SE a continuación para obtener más información sobre cómo resolver el problema de los diamantes:

    ¿Cuáles son las diferencias entre las clases abstractas y las interfaces en Java 8?

  3. Herencia múltiple de tipo: capacidad de una clase para implementar más de una interfaz.

    Dado que la interfaz no contiene campos mutables, aquí no tiene que preocuparse por los problemas que resultan de la herencia múltiple de estados.