¿Son los valores predeterminados en JDK 8 una forma de herencia múltiple en Java?

83

Una nueva característica que viene en JDK 8 le permite agregar a una interfaz existente mientras conserva la compatibilidad binaria.

La sintaxis es como

public interface SomeInterface() {
  void existingInterface();
  void newInterface() default SomeClass.defaultImplementation;
}

De esta manera, para todas las implementaciones existentes de SomeInterfacecuando se actualizan a esta nueva versión, no todas tienen errores de compilación repentinamente newInterface().

Si bien esto es bueno, ¿qué sucede cuando implementa dos interfaces que han agregado un nuevo método predeterminado que no implementó? Dejame explicarte con un ejemplo.

public interface Attendance {
   boolean present() default DefaultAttendance.present;
}

public interface Timeline {
   boolean present() default DefaultTimeline.present;
}

public class TimeTravelingStudent implements Attendance, Timeline {

}

// which code gets called?
new TimeTravelingStudent().present();

¿Esto ya se ha definido como parte de JDK 8?

Encontré a los dioses de Java hablando de algo similar aquí http://cs.oswego.edu/pipermail/lambda-lib/2011-February/000068.html , pero es parte de una lista de correo privada y no puedo preguntarles directamente.

Consulte esto para obtener más detalles sobre cómo se utilizarán los valores predeterminados en JDK 8 y extender la interfaz de la colección para admitir lambdas: https://oracleus.wingateweb.com/published/oracleus2011/sessions/25066/25066_Cho223662.pdf

Pirolístico
fuente
La sesión de video para ver está aquí: medianetwork.oracle.com/video/player/1113272518001 Este es el diseñador hablando sobre la función llamada Extensiones virtuales. También habla de cómo esto no rompe la compatibilidad con versiones anteriores.
Peter Lawrey
Entonces, la respuesta a mi ejemplo es que actualmente obtiene un error del compilador. Pero están abiertos a otras soluciones.
Pirolístico
Otro material útil para esto es cr.openjdk.java.net/~briangoetz/lambda/…
MohamedSanaulla
Nota al margen: la sintaxis final para las implementaciones predeterminadas de los métodos de interfaz resultó ser diferente (bloque de código en lugar de una referencia a una clase externa).
Joachim Sauer
4
Java siempre ha tenido múltiples tipos de herencia . Los métodos predeterminados agregan una herencia múltiple de comportamiento , pero no de estado . (La herencia múltiple de estado en lenguajes como C ++ es de donde proviene la mayor parte de los problemas).
Brian Goetz

Respuestas:

66

La respuesta a la operación duplicada es:

Para resolver el problema de herencia múltiple, una clase que implemente dos interfaces que proporcionen una implementación predeterminada para el mismo nombre de método y firma debe proporcionar una implementación del método. [Articulo completo]

Mi respuesta a su pregunta es: Sí, es una forma de herencia múltiple, porque puede heredar el comportamiento de diferentes padres. Lo que falta es heredar estados, es decir, atributos.

H-Man2
fuente
2
+1: cuando hay un conflicto, se necesitará una implementación más específica sobre una menos específica, lo que le permitirá especificar cuál debería ser si hay un conflicto.
Peter Lawrey
@ H-Man2 No lo entiendo. Si eso es cierto, significa que rompería la compatibilidad binaria. Quizás eso no sea tan malo como romper la compatibilidad binaria para evitar la herencia múltiple, romper la compatibilidad binaria apesta.
Pirolístico
@PeterLawrey ¿cuál es más específico en mi ejemplo?
Pirolístico
@Pyrolistical: No, no rompe la compatibilidad, porque el compilador puede traducir la implementación predeterminada a una llamada de método normal. Creo que es más una macro que una herencia real, pero puede simular aspectos de la herencia múltiple. Quizás el video de Peter proporcione una respuesta más detallada.
H-Man2
en realidad podemos conseguir alrededor de los estados que faltan por tener getters y setters abstractos, la clase que implementa puede agregar los estados ...
vikkyhacks
8

Sé que esta es una publicación antigua, pero como estoy trabajando con estas cosas ...

Tendrá un error del compilador, indicándole que:

 La clase TimeTravelingStudent hereda valores predeterminados no relacionados para el presente () de los tipos Asistencia y la referencia de la línea de tiempo al presente es ambigua, tanto el método presente () en la línea de tiempo como el método presente () en la coincidencia de asistencia.

Enkk
fuente
7

Hay dos escenarios:

1) Primero, eso se mencionó, donde no hay una interfaz más específica

public interface A {
   default void doStuff(){ /* implementation */ }
}

public interface B {
   default void doStuff() { /* implementation */ } 
}

public class C implements A, B {
// option 1: own implementation
// OR
// option 2: use new syntax to call specific interface or face compilation error
  void doStuff(){
      B.super.doStuff();
  }
}

2) Segundo, cuando HAY una interfaz más específica:

   public interface A {
       default void doStuff() { /* implementation */ } 
    }

    public interface B extends A {
       default void doStuff() { /* implementation */ } 
    }

    public class C implements A, B {
    // will use method from B, as it is "closer" to C
    }
Andrejs
fuente
4

Mi respuesta a su pregunta es: Sí, es una forma de herencia múltiple, porque puede heredar el comportamiento de diferentes padres. Lo que falta es heredar estados, es decir, atributos.

Sí, pero puede agregar captadores y definidores a su interfaz que las clases de implementación deben implementar. Sin embargo, las clases de implementación no heredan atributos. Entonces, AFAICS, es más como una solución de estilo de rasgo que una solución de estilo de herencia múltiple.

OlliP
fuente
4

En resumen: es un error de tiempo de compilación, debe anular el método manualmente en la implementación.


Propósito del método predeterminado

El propósito principal de introducir el método predeterminado en Java 8 es hacer que la interfaz sea extensible, sin romper las implementaciones existentes (hay tantas bibliotecas Java de terceros).

Y multiple inheritancecomo en C ++ en realidad se pretende evitar, ese definitivamente no es el propósito del método predeterminado en Java.


Cómo anular

2 opciones:

  • Anula el método, con su propia lógica.
  • Anule el método, llame a uno de los métodos de la interfaz a través de superformato:<interface_name>.super.<method_name>();

Consejos:

  • El método de la interfaz está predeterminado en público, así que no olvide agregar una publicpalabra clave cuando la anule.
Eric Wang
fuente
2

Si alguien todavía está buscando una respuesta, en caso de que una clase implemente dos interfaces con el mismo método predeterminado, entonces la clase necesita resolver la falta de ambigüedad proporcionando una implementación propia. Consulte este tutorial para obtener más detalles sobre cómo funciona la herencia en los métodos predeterminados.

Mithil-studytrails
fuente
0

"¿Cómo distinguiremos los métodos?" Fue una pregunta que se puso en Stackoverflow y se refirió a esta pregunta métodos concretos en interfaces Java1.8

El siguiente es un ejemplo que debería responder a esa pregunta:

interface A{
default public void m(){
System.out.println("Interface A: m()");
}
}

interface B{
default public void m(){
System.out.println("Interface B: m()");
}
}

 class C implements A,B { 

 public void m(){
  System.out.println("Concrete C: m()");   
 }

public static void main(String[] args) {
   C aC = new C();
   aC.m();
   new A(){}.m();
   new B(){}.m();
}
}

La clase C anterior debe implementar su propio método concreto de las interfaces A y B. A saber:

 public void m(){
  System.out.println("Interface C: m()");   
 }

Para llamar a una implementación concreta de un método desde una interfaz específica , puede crear una instancia de la interfaz y llamar explícitamente al método concreto de esa interfaz

Por ejemplo, el siguiente código llama a la implementación concreta del método m () desde la interfaz A :

new A(){}.m();

El resultado de lo anterior sería:

Interfaz A: m ()

Mark Burleigh
fuente
-1

Hasta donde yo lo veo, no es una herencia múltiple porque son apátridas. Por lo tanto, los métodos de extensión virtual no admiten la funcionalidad completa de objetos o clases.

Pedro
fuente