Java no permite la herencia múltiple, pero permite implementar múltiples interfaces. ¿Por qué?
Java no permite la herencia múltiple, pero permite implementar múltiples interfaces. ¿Por qué?
Respuestas:
Debido a que las interfaces especifican solo lo que 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.
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 un entorno de "oscuridad". Ambos tienen un método on (). (Uno tiene un off (), el otro no). Si quiero crear una clase que sea una subclase de ambos ... como puede ver, este es un problema que realmente podría explotar en mi cara aquí .
Entonces, uno de los problemas principales es que si tiene dos clases principales, pueden tener implementaciones diferentes de la misma característica, o posiblemente dos características diferentes con el mismo nombre, como en el ejemplo de mi instructor. Luego debe decidir cuál va a utilizar su subclase. Ciertamente, hay formas de manejar esto, C ++ lo hace, pero los diseñadores de Java sintieron que esto complicaría las cosas.
Sin embargo, con una interfaz, está 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 varias interfaces causen conflictos difíciles que deben resolverse que las clases principales múltiples.
Debido a que la herencia se usa en exceso incluso cuando no puedes decir "oye, ese método parece útil, también extenderé esa clase".
public class MyGodClass extends AppDomainObject, HttpServlet, MouseAdapter,
AbstractTableModel, AbstractListModel, AbstractList, AbstractMap, ...
La respuesta a esta pregunta radica en el funcionamiento interno del compilador de Java (encadenamiento del constructor). Si vemos el funcionamiento interno del compilador de Java:
public class Bank {
public void printBankBalance(){
System.out.println("10k");
}
}
class SBI extends Bank{
public void printBankBalance(){
System.out.println("20k");
}
}
Después de compilar este aspecto:
public class Bank {
public Bank(){
super();
}
public void printBankBalance(){
System.out.println("10k");
}
}
class SBI extends Bank {
SBI(){
super();
}
public void printBankBalance(){
System.out.println("20k");
}
}
cuando ampliamos la clase y creamos un objeto de la misma, una cadena de constructores se ejecutará hasta la Object
clase.
El código anterior se ejecutará bien. pero si tenemos otra clase llamada Car
que se extiende Bank
y una clase híbrida (herencia múltiple) llamada SBICar
:
class Car extends Bank {
Car() {
super();
}
public void run(){
System.out.println("99Km/h");
}
}
class SBICar extends Bank, Car {
SBICar() {
super(); //NOTE: compile time ambiguity.
}
public void run() {
System.out.println("99Km/h");
}
public void printBankBalance(){
System.out.println("20k");
}
}
En este caso (SBICar) no se podrá crear la cadena del constructor ( ambigüedad de tiempo de compilación ).
Para las interfaces esto está permitido porque no podemos crear un objeto de él.
Para conocer el nuevo concepto default
y static
método, consulte el valor predeterminado en la interfaz .
Espero que esto resuelva tu consulta. Gracias.
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 se pueden hacer por composición o usando clases internas. Por lo tanto, la herencia múltiple está prohibida ya que trae más problemas que ganancias.
ToyotaCar
y HybridCar
ambos derivan Car
y anulan Car.Drive
, y si PriusCar
heredan ambos pero no anulanDrive
, el sistema no tendría forma de identificar lo que Car.Drive
debería hacer el virtual . Las interfaces evitan este problema al evitar la condición en cursiva anterior.
void UseCar(Car &foo)
; no se puede esperar que incluya desambiguación entre ToyotaCar::Drive
y HybridCar::Drive
(ya que a menudo no debe saber ni preocuparse de que esos otros tipos existan ). Un lenguaje podría, como lo hace C ++, requerir que ese código con el ToyotaCar &myCar
deseo de pasarlo UseCar
primero deba emitirse a cualquiera de los dos HybridCar
o ToyotaCar
, pero desde ((Car) (HybridCar) myCar) .Drive` y ((Car)(ToyotaCar)myCar).Drive
haría cosas diferentes, eso implicaría que los upcasts no preservaban la identidad.
Puede encontrar una respuesta precisa para esta consulta en la página de documentación de Oracle sobre herencia múltiple
Herencia múltiple de estado: capacidad 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 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 crea un objeto instanciando esa clase, ese objeto heredará campos de todas las superclases de la clase. Causará dos problemas.
Herencia múltiple de implementación: capacidad de heredar definiciones de métodos de múltiples clases
Problemas con este enfoque: nombre de conflictos 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 el lanzamiento 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 detalles sobre la resolución del problema del diamante:
¿Cuáles son las diferencias entre las clases abstractas y las interfaces en Java 8?
Herencia múltiple de tipo: capacidad de una clase para implementar más de una interfaz.
Dado que la interfaz no contiene campos mutables, no tiene que preocuparse por los problemas que resultan de la herencia de estado múltiple aquí.
Se dice que el estado de los objetos se refiere con respecto a los campos en él y sería ambiguo si se heredaran demasiadas clases. Aqui esta el link
http://docs.oracle.com/javase/tutorial/java/IandI/multipleinheritance.html
Java admite herencia múltiple solo a través de interfaces. Una clase puede implementar cualquier número de interfaces, pero solo puede extender una clase.
La herencia múltiple no es compatible porque conduce a un problema mortal de diamantes. Sin embargo, se puede resolver, pero conduce a un sistema complejo, por lo que los fundadores de Java han eliminado la herencia múltiple.
En un libro blanco titulado "Java: una descripción general" de 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 confusas y poco utilizadas de C ++ que, según nuestra experiencia, traen más dolor que beneficio. Esto consiste principalmente en la sobrecarga del operador (aunque sí tiene sobrecarga del método), herencia múltiple y extensas coacciones automáticas".
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 herencia múltiple fue que conducía a más problemas de los que valía la pena.
Una interfaz es un contrato de cosas que su clase tiene que implementar. No obtienes ninguna funcionalidad de la interfaz. La herencia le permite heredar la funcionalidad de una clase principal (y en herencia múltiple, eso puede ser extremadamente confuso).
Permitir múltiples interfaces le permite usar Patrones de diseño (como Adaptador) para resolver los mismos tipos de problemas que puede resolver usando la herencia múltiple, pero de una manera mucho más confiable y predecible.
D1
y D2
ambos heredan de B
, y cada uno anula una función f
, y si obj
es una instancia de un tipo S
que hereda de ambos D1
y D2
no anula f
, entonces emitir una referencia S
a D1
debería producir algo cuyo f
uso D1
anule, y emitir a B
no debería cambia eso. Del mismo modo, emitir una referencia S
a D2
debería producir algo que f
usa la D2
anulación, y emitir a B
no debería cambiar eso. Si un idioma no necesita permitir que se agreguen miembros virtuales ...
Como este tema no está cerrado, publicaré esta respuesta, espero que esto ayude a alguien a entender por qué Java no permite la herencia múltiple.
Considere la siguiente clase:
public class Abc{
public void doSomething(){
}
}
En este caso, la clase Abc no extiende nada ¿verdad? No tan rápido, esta clase implícita extiende la clase Object, clase base que permite que todo funcione en Java. Todo es un objeto.
Si intenta utilizar la clase anterior se verá que su IDE permite utilizar métodos como: equals(Object o)
, toString()
, etc, pero no declaró esos métodos, vinieron de la clase baseObject
Tu podrías intentar:
public class Abc extends String{
public void doSomething(){
}
}
Esto está bien, porque su clase no se extenderá implícitamente, Object
sino que se extenderá String
porque usted lo dijo. 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 ToString ().
Ahora imagine la siguiente clase:
public class Flyer{
public void makeFly(){
}
}
public class Bird extends Abc, Flyer{
public void doAnotherThing(){
}
}
Nuevamente, la clase Flyer
implícita extiende el Objeto que tiene el método toString()
, cualquier clase tendrá este método ya que todos se extienden Object
indirectamente, entonces, si llama toString()
desde Bird
, ¿qué toString()
Java tendría que usar? ¿De 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étodos" construyeron la idea de interfaz , básicamente podría pensar que son una clase abstracta que no extiende el Objeto indirectamente . Dado que son abstractos , deberán ser implementados por una clase, que es un objeto(no se puede instanciar una interfaz solo, debe ser implementado por una clase), por lo que todo continuará funcionando bien.
Para diferenciar las clases de las interfaces, la palabra clave implements estaba reservada solo para interfaces.
Puede implementar cualquier interfaz que desee en la misma clase, ya que no extiende nada de forma predeterminada (pero puede crear una interfaz que extienda otra interfaz, pero nuevamente, la interfaz "padre" no extiende Objeto "), por lo que una interfaz es solo una interfaz y no sufrirán " colisiones de firma de métodos ", si lo hacen, el compilador le enviará una advertencia y solo tendrá que cambiar la firma del método para solucionarlo (firma = nombre del método + parámetros + 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
}
Porque una interfaz es solo un contrato. Y una clase es en realidad un contenedor de datos.
Por ejemplo, dos clases A, B con el mismo método m1 (). Y la clase C extiende tanto a A como a B.
class C extends A, B // for explaining purpose.
Ahora, la clase C buscará la definición de m1. Primero, buscará en la clase si no encontró, luego verificará en la clase de los padres. Ambos A, B tienen la definición Entonces, aquí se produce la ambigüedad, qué definición debería elegir. Entonces JAVA NO APOYA LA HERENCIA MÚLTIPLE.
Java no admite herencia múltiple por dos razones:
Object
clase. Cuando hereda de más de una superclase, la subclase obtiene la ambigüedad de adquirir la propiedad de la clase Object.super()
a invocar el constructor de la clase supper. Si la clase tiene más de una superclase, se confunde.Entonces, cuando una clase se extiende desde más de una superclase, obtenemos un error de tiempo de compilación.
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 extiende A y B. ¿Qué pasaría si alguien llamara C.getSomething? No hay forma de determinar a qué método llamar.
Las interfaces básicamente solo especifican qué métodos debe contener una clase de implementación. Una clase que implementa múltiples interfaces solo significa que esa clase tiene que implementar los métodos de todas esas interfaces. Whci no conduciría a ningún problema como se describió 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 llama desde un objeto de clase hijo, habrá 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.
Java no admite herencia múltiple, trayectoria múltiple 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.
Enlace de referencia: https://plus.google.com/u/0/communities/102217496457095083679
De una manera simple que todos sabemos, podemos heredar (extender) una clase pero podemos implementar tantas interfaces ... eso es porque en las interfaces no damos una implementación, solo decimos la funcionalidad. supongo que si Java se extiende tantas clases y los que tienen mismos métodos .. en este punto si tratamos de invocar el método superclase de la clase sub qué método supone que debe funcionar ??, compilador se confunda ejemplo: - tratar de múltiples extiende pero en las interfaces de esos métodos no tienen cuerpos, debemos implementarlos en una subclase ... intente con varios implementos para que no se preocupe ...
* Esta es una respuesta simple ya que soy un principiante en Java *
Considere que hay tres clases X
, Y
y Z
.
Entonces estamos heredando like X extends Y, Z
And both Y
y Z
está teniendo un método alphabet()
con el mismo tipo de retorno y argumentos. Este método alphabet()
en Y
dice para mostrar el primer alfabeto y el alfabeto de método en Z
dice mostrar el último alfabeto . Entonces aquí viene la ambigüedad cuando alphabet()
se llama por X
. ¿Si dice mostrar el primer alfabeto o el último ? Entonces, Java no es compatible con la herencia múltiple. En el caso de las interfaces, considere Y
y Z
como interfaces. Por lo tanto, ambos contendrán la declaración del método alphabet()
pero no la definición. No indicará si se debe mostrar el primer alfabeto o el último alfabeto o cualquier otra cosa, pero solo declarará un métodoalphabet()
. Entonces no hay razón para aumentar la ambigüedad. Podemos definir el método con todo lo que queramos dentro de la clase X
.
En una palabra, en la definición de Interfaces se realiza después de la implementación, por lo que no hay confusión.