2009-06-15 28 views
93

Sé que no se permite la herencia múltiple en Java y C#. Muchos libros solo dicen que la herencia múltiple no está permitida. Pero puede implementarse mediante el uso de interfaces. No se discute nada sobre por qué no está permitido. ¿Alguien puede decirme exactamente por qué no está permitido?¿Por qué no se permite la herencia múltiple en Java o C#?

+1

igual para señalar que * hay * frameworks que permiten el comportamiento tipo MI en las clases C#. Y, por supuesto, usted tiene la opción de tener mezclas mixtas sin estado (usando métodos de extensiones), siendo apátridas, sin embargo, no son muy útiles. –

+0

Que las interfaces tienen algo que ver con la herencia es una ilusión creada por la sintaxis del lenguaje. La herencia se supone que te hará más rico. Nada como eso para una interfaz, no heredas la sentadilla y te hace significativamente más pobre. Has heredado la deuda de juego del tío Harry, tienes más trabajo por hacer para implementar la interfaz. –

Respuesta

128

La respuesta corta es: porque los diseñadores del lenguaje decidieron no hacerlo.

Básicamente, parecía que tanto el .NET y diseñadores de Java no permiten la herencia múltiple, porque razonaron que la adición de MI añadió demasiada complejidad a los idiomas al tiempo que proporciona muy poco beneficio.

Para una lectura más divertida y profunda, hay algunos artículos disponibles en la web con entrevistas de algunos de los diseñadores de idiomas. Por ejemplo, para .NET, Chris Brumme (que trabajaba en la EM en el CLR) ha explicado las razones por las que decidieron no:

  1. diferentes idiomas en realidad tienen diferentes expectativas de cómo MI obras. Por ejemplo, cómo se resuelven los conflictos y si las bases duplicadas están fusionadas o son redundantes. Antes de que podamos implementar MI en el CLR, tenemos que hacer una encuesta de todos los idiomas, figura fuera de los conceptos comunes, y decidir cómo expresarlos en un idioma neutral. También podríamos decidir si MI pertenece al CLS y lo que esto significaría para idiomas que no desean este concepto (presumiblemente VB.NET, por ejemplo). Del curso , ese es el negocio en el que estamos como lenguaje de ejecución común, pero aún no lo hemos hecho para MI .

  2. El número de lugares donde MI es realmente apropiado es en realidad bastante pequeño. En muchos casos, la herencia de la interfaz múltiple puede hacer que el trabajo se realice en su lugar. En otros casos, puede poder usar la delegación de encapsulación y .Si tuviéramos que agregar una construcción ligeramente diferente, como mixins, ¿sería realmente más potente?

  3. La herencia de implementación múltiple inyecta mucha complejidad en la implementación . Esta complejidad impactos de fundición, diseño, envío, acceso de campo, serialización, identidad comparaciones, verificabilidad, reflexión, genéricos, y probablemente muchos otros lugares.

You can read the full article here.

Para Java, se puede leer this article:

Las razones para omitir múltiples herencia del lenguaje Java provienen en su mayoría de la "simple, objeto orientado y familiar "objetivo". Como un lenguaje simple , los creadores de Java querían un lenguaje que la mayoría de los desarrolladores podían captar sin una extensa formación en . Con ese fin, trabajaron para hacer que el lenguaje sea similar a C++ como posible (familiar) sin llevar sobre la complejidad innecesaria de C++ (simple).

Según la opinión de los diseñadores, la herencia múltiple causa más problemas y confusión de lo que resuelve. Entonces cortaron herencia múltiple del lenguaje (del mismo modo que cortaron la sobrecarga del operador ). La amplia experiencia de los diseñadores en el C++ les enseñó que herencia múltiple simplemente no valía el dolor de cabeza.

+8

Buena comparación. Bastante indicativo de los procesos de pensamiento que subyacen en ambas plataformas, creo. – CurtainDog

12

La principal (aunque no la única) razón por la que las personas se alejan de MI es el llamado "problema de diamante" que conduce a la ambigüedad en su implementación. Esta wikipedia article lo discute y explica mejor que yo. MI también puede conducir a un código más complejo, y muchos diseñadores de OO afirman que no necesita un MI, y si lo usa, su modelo probablemente sea incorrecto. No estoy seguro de estar de acuerdo con este último punto, pero mantener las cosas simples siempre es un buen plan.

81

Herencia múltiple de implementación es lo que no está permitido.

El problema es que el compilador/tiempo de ejecución no puede encontrar qué hacer si tiene una clase Cowboy y una clase Artist, ambas con implementaciones para el método draw(), y luego intenta crear un nuevo tipo CowboyArtist. ¿Qué sucede cuando llamas al método draw()? ¿Alguien está muerto en la calle, o tienes una hermosa acuarela?

Creo que se llama el problema de herencia de doble diamante.

+3

¡el doble diamante es la cerveza! ;) –

+71

Usted obtiene una hermosa acuarela de alguien muerto en la calle :-) –

+0

¿Es este el único problema? Creo que no estoy seguro de que C++ resuelva este problema con la palabra clave virtual, ¿es así? No soy bueno en C++ –

8

En C++ la herencia múltiple era un gran dolor de cabeza cuando se utilizaba incorrectamente. Para evitar los problemas de diseño populares, se forzaron múltiples interfaces "herencia" en lugar de idiomas modernos (java, C#).

5

Otra razón es que la herencia única hace que la conversión sea trivial, sin emitir instrucciones de ensamblador (aparte de verificar la compatibilidad de los tipos cuando sea necesario). Si tuvieras herencia múltiple, necesitarías averiguar en qué parte de la clase infantil comienza un padre determinado. Entonces, el rendimiento es sin duda un beneficio (aunque no el único).

3

En los viejos tiempos ('70) cuando la informática era más ciencia y menos producción en masa, los programadores tuvieron tiempo para pensar en un buen diseño y una buena implementación y como resultado los productos (programas) tenían alta calidad (ej. Diseño e implementación TCP/IP). Hoy en día, cuando todo el mundo está programando, y los gerentes están cambiando las especificaciones antes de los plazos, cuestiones sutiles como la descrita en el enlace de la wikipedia de la publicación de Steve Haigh son difíciles de rastrear; por lo tanto, la "herencia múltiple" está limitada por el diseño del compilador. Si te gusta, aún puedes usar C++ .... y tener toda la libertad que quieras :)

+4

... incluida la libertad de dispararse en el pie, varias veces;) –

4

Tomo la declaración de que "herencia múltiple no está permitida en Java" con una pizca de sal.

Herencia múltiple se define cuando un "Tipo" hereda de más de un "Tipos". Y las interfaces también se clasifican como tipos ya que tienen un comportamiento.Entonces Java tiene herencia múltiple. Solo que es más seguro.

+6

Pero no hereda de una interfaz, la implementa. Las interfaces no son clases. – Blorgbeard

+2

Sí, pero la herencia nunca se definió tan estrechamente, excepto en algunos libros preliminares. Y creo que deberíamos mirar más allá de la gramática de esto. Ambos hacen lo mismo, y las interfaces se "inventaron" solo para ese motivo. –

+0

Upvoting para eliminar el -1. Tienes un buen punto. –

8

herencia múltiple es

  • difícil de entender
  • difíciles de depurar (por ejemplo, si se mezclan las clases de múltiples marcos que tienen métodos con nombres idénticos en el fondo, bastante sinergias inesperadas pueden ocurrir)
  • fácil de mal uso
  • en realidad no que útil
  • difícil de implementar, especialmente si usted quiere que se haga correctamente y eficazmente

Por lo tanto, se puede considerar una buena elección para no incluyen herencia múltiple en el lenguaje Java.

+2

No estoy de acuerdo con todo lo anterior, habiendo trabajado con el sistema de objetos Common Lisp. –

+1

Los lenguajes dinámicos no cuentan ;-) En cualquier sistema tipo Lisp, usted tiene un REPL que hace que la depuración sea más fácil. Además, CLOS (tal como lo entiendo, nunca lo he usado realmente, solo lo leí) es un sistema de metaobjetos, con mucha flexibilidad y una actitud propia. Pero considere un lenguaje compilado estáticamente como C++, donde el compilador genera una búsqueda de métodos diabólicamente compleja usando múltiples tablas (posiblemente superpuestas): en dicha implementación, descubrir qué implementación de un método se invocó podría ser una no tan trivial tarea. – mfx

13

Porque Java tiene una filosofía de diseño muy diferente de C++. (No voy a discutir C# aquí.)

Al diseñar C++, Stroustrup quería incluir funciones útiles, independientemente de cómo podrían ser mal utilizadas. Es posible arruinarlo a gran velocidad con herencia múltiple, sobrecarga de operadores, plantillas y varias otras características, pero también es posible hacer algunas cosas muy buenas con ellos.

La filosofía del diseño de Java es enfatizar la seguridad en los constructos del lenguaje. El resultado es que hay cosas que son mucho más difíciles de hacer, pero puede estar mucho más seguro de que el código que está viendo significa lo que cree que es.

Además, Java fue en gran medida una reacción de C++ y Smalltalk, los lenguajes más conocidos de OO. Hay muchos otros lenguajes OO (Common Lisp fue en realidad el primero en ser estandarizado), con diferentes sistemas OO que manejan mejor MI.

Sin mencionar que es completamente posible hacer MI en Java, usando interfaces, composición y delegación. Es más explícito que en C++, y por lo tanto, es más difícil de usar, pero le proporcionará algo que es más probable que comprenda a primera vista.

No hay una respuesta correcta aquí. Hay diferentes respuestas, y cuál es mejor para una situación dada depende de las aplicaciones y las preferencias individuales.

3

Java tiene un concepto, es decir, polimorfismo. Hay 2 tipos de polimorfismo en java. Hay sobrecarga de método y anulación de método. Entre ellos, la anulación de método ocurre con la relación de superclase y subclase. Si estamos creando un objeto de una subclase e invocando el método de superclase, y si la subclase extiende más de una clase, ¿qué método de superclase debería llamarse?

O, al llamar al constructor de la superclase por super(), ¿de qué constructor de clase superior se llamará?

Estas decisiones son imposibles por las características actuales de la API de Java. por lo que la herencia múltiple no está permitida en Java.

+0

Fundamentalmente, el sistema de tipos de Java asume que cada instancia de objeto tiene un tipo, fundir un objeto en un supertipo siempre funcionará y conservará las referencias, y al convertir una referencia a un subtipo se conservará la referencia si la instancia es de ese subtipo o un subtipo de eso. Tales suposiciones son útiles, y no creo que sea posible permitir la herencia múltiple generalizada de una manera consistente con ellos. – supercat

4

La carga dinámica de clases dificulta la implementación de la herencia múltiple.

En java, en realidad, evitaron la complejidad de la herencia múltiple utilizando una herencia e interfaz únicas. La complejidad de la herencia múltiple es muy alta en una situación como a continuación se explica

problema de diamante de la herencia múltiple. Tenemos dos clases B y C que heredan de A. Supongamos que B y C están anulando un método heredado y proporcionan su propia implementación. Ahora D hereda de B y C haciendo herencia múltiple. D debe heredar ese método reemplazado, jvm no puede decidir qué método reemplazado se usará?

En C++ las funciones virtuales se utilizan para manejar y tenemos que hacerlo explícitamente.

Esto se puede evitar mediante el uso de interfaces, no hay cuerpos de métodos. No se pueden crear instancias de interfaces: solo pueden implementarse por clases o extenderse por otras interfaces.

17

Motivo: Java es muy popular y fácil de codificar, debido a su simplicidad.

Así que, lo que sea que a los desarrolladores de Java les parezca difícil y complicado de entender para los programadores, trataron de evitarlo. Uno de esos tipos de propiedad es la herencia múltiple.

  1. evitaron punteros
  2. evitaban la herencia múltiple.

Problema con la herencia múltiple: Diamante problema.

Ejemplo:

  1. Supongamos que la clase A está teniendo una diversión método(). la clase B y la clase C derivan de la clase A.
  2. Y tanto las clases B y C, anulan el método fun().
  3. Supongamos ahora que la clase D hereda tanto de clase B, y C. (justo Asunción)
  4. crear el objeto para la clase D.
  5. D d = new D();
  6. y tratar de acceder a d.fun(); => ¿llamará a la diversión de la clase B() o la diversión de la clase C()?

Esta es la ambigüedad existente en el problema de los diamantes.

No es imposible resolver este problema, pero crea más confusión y complejidades para el programador mientras lo lee. Causa más problemas de los que intenta resolver.

Nota: De todos modos, siempre puede implementar herencia múltiple indirectamente mediante el uso de interfaces.

3

En realidad, la herencia múltiple surgirá a la complejidad si las clases heredadas tienen la misma función. es decir, el compilador tendrá una confusión que uno debe elegir (problema de diamante). Así que en Java esa complejidad se eliminó y dio interfaz para obtener la funcionalidad como herencia múltiple.Podemos usar la interfaz

1

La herencia múltiple no está permitida en Java directamente, pero a través de las interfaces está permitido.

Motivo:

herencia múltiple: se introduce una mayor complejidad y ambigüedad.

Interfaces: Las interfaces son clases completamente abstractas en Java que le proporcionan una manera uniforme para delinear adecuadamente la estructura o funcionamiento interno de su programa desde su interfaz a disposición del público, con la consecuencia de una mayor cantidad de flexibilidad y reutilizable código, así como más control sobre cómo crear e interactuar con otras clases.

Más precisamente, son una construcción especial en Java con la característica adicional que le permite realizar un tipo de herencia múltiple, es decir, clases que se pueden actualizar a más de una clase.

Tomemos un ejemplo simple.

  1. Supongamos que hay 2 clases superclases A y B con los mismos nombres de método pero diferentes funcionalidades. A través del siguiente código con la palabra clave (extends), la herencia múltiple no es posible.

    public class A        
        { 
         void display() 
         { 
          System.out.println("Hello 'A' "); 
         } 
        } 
    
        public class B        
         { 
         void display() 
          { 
          System.out.println("Hello 'B' "); 
          } 
         } 
    
        public class C extends A, B // which is not possible in java 
        { 
         public static void main(String args[]) 
         { 
          C object = new C(); 
          object.display(); // Here there is confusion,which display() to call, method from A class or B class 
         } 
        } 
    
  2. Pero a través de interfaces, con (aperos) palabra clave herencia múltiple es posible.

    interface A 
        { 
         // display() 
        } 
    
    
    interface B 
        { 
         //display() 
        } 
    
    class C implements A,B 
        { 
         //main() 
         C object = new C(); 
         (A)object.display();  // call A's display 
    
         (B)object.display(); //call B's display 
        } 
    } 
    
-3

Imagínese este Ejemplo: tengo una clase Shape1

Tiene CalcualteArea método:

Class Shape1 
{ 

public void CalculateArea() 

    { 
     // 
    } 
} 

Hay otra clase Shape2 que uno también tiene mismo método

Class Shape2 
{ 

public void CalculateArea() 

    { 

    } 
} 

Ahora tengo un círculo de clase para niños, se deriva tanto de Shape1 como de Shape2;

public class Circle: Shape1, Shape2 
{ 
} 

Ahora cuando se crea objetos para Círculo, y llamar al método, el sistema no sabe qué método calcular el área a ser llamado. Ambos tienen las mismas firmas. Entonces el compilador se confundirá. Es por eso que no se permiten herencias múltiples.

Pero puede haber múltiples interfaces porque las interfaces no tienen definición de método. Incluso ambas interfaces tienen el mismo método, ambas no tienen ninguna implementación y siempre se ejecutará el método en la clase hija.

+0

el diseñador de lenguaje puede dar una llamada a método explícito como lo hacen en la interfaz. ¡No hay tal punto! Otra razón es ¿qué hay de la clase abstracta con métodos abstractos ahora cómo lo considera? –

0

¿Alguien me puede decir exactamente por qué no está permitido?

puede encontrar respuesta por parte de esta documentación link

Una de las razones por qué el lenguaje de programación Java no permite que usted extienda más de una clase es evitar los problemas de herencia múltiple del 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.

  1. ¿Qué ocurre si los métodos o constructores de diferentes superclases ejemplifican el mismo campo?

  2. ¿Qué método o constructor tendrá prioridad?

A pesar de que la herencia múltiple de estado ahora se permite, todavía se puede implementar

La herencia múltiple de tipo: Capacidad de una clase para implementar más de una interfaz.

La herencia múltiple de aplicación (a través de métodos predeterminados en interfaces): Capacidad para heredar definiciones de métodos de varias clases

Consulte a esta pregunta SE relacionados para obtener información adicional:

Multiple Inheritance Ambiguity with Interface

Cuestiones relacionadas