¿Cuál es la implementación "predeterminada" del método definido en una interfaz?

91

En la interfaz de colección encontré un método llamado removeIf()que contiene su implementación.

default boolean removeIf(Predicate<? super E> filter) {
    Objects.requireNonNull(filter);  
    boolean removed = false;  
    final Iterator<E> each = iterator();   
    while (each.hasNext()) {  
        if (filter.test(each.next())) {  
            each.remove();  
            removed = true;  
        }  
    }  
    return removed;  
}  

Quiero saber si hay alguna forma de definir el cuerpo del método en una interfaz.
¿Cuál es la defaultpalabra clave y cómo funciona?

gifpif
fuente
3
vea esta publicación sobre el zeroturnaround.com/rebellabs/java-8-explained-default-methods/…
emeraldjava

Respuestas:

162

De https://dzone.com/articles/interface-default-methods-java

Java 8 introduce una nueva característica de "Método predeterminado" o (métodos de defensa), que permite al desarrollador agregar nuevos métodos a las interfaces sin romper la implementación existente de estas interfaces. Proporciona flexibilidad para permitir la implementación de definición de interfaz que se utilizará de forma predeterminada en la situación en la que una clase concreta no proporcione una implementación para ese método.

public interface A {
    default void foo(){
       System.out.println("Calling A.foo()");
    }
}

public class ClassAB implements A {
}

Hay una pregunta común que las personas hacen sobre los métodos predeterminados cuando escuchan sobre la nueva función por primera vez:

¿Qué pasa si la clase implementa dos interfaces y ambas interfaces definen un método predeterminado con la misma firma?

Ejemplo para ilustrar esta situación:

public interface A {  
    default void foo(){  
        System.out.println("Calling A.foo()");  
    }  
}

public interface B {
    default void foo(){
        System.out.println("Calling B.foo()");
    }
}


public class ClassAB implements A, B {

}  

Este código no se puede compilar con el siguiente resultado:

java: class Clazz inherits unrelated defaults for foo() from types A and B

Para solucionarlo, en Clazz, tenemos que resolverlo manualmente anulando el método conflictivo:

public class Clazz implements A, B {
    public void foo(){}
}

Pero, ¿qué sucede si quisiéramos llamar a la implementación predeterminada del método foo () desde la interfaz A en lugar de implementar la nuestra?

Es posible referirse a A # foo () de la siguiente manera:

public class Clazz implements A, B {
    public void foo(){
       A.super.foo();
    }
}
gifpif
fuente
18
Gracias, muy buena exposición. Respondiste a todas mis preguntas antes de que tuviera la oportunidad de hacerlas.
Jeff Hutchins
¿Por qué no usar abstracto en su lugar?
Astolfo Hoscher
1
@AstolfoHoscher Solo puede extender una clase, pero puede implementar múltiples interfaces.
Charles Wood
49

Estos métodos se denominan métodos predeterminados. El método predeterminado o el método Defender es una de las características recién agregadas en Java 8.

Se utilizarán para permitir que un método de interfaz proporcione una implementación utilizada como predeterminada en el caso de que una clase concreta no proporcione una implementación para ese método.

Entonces, si tiene una interfaz, con un método predeterminado:

public interface Hello {
    default void sayHello() {
        System.out.println("Hello");
    }
}

La siguiente clase es perfectamente válida:

public class HelloImpl implements Hello {

}

Si crea una instancia de HelloImpl:

Hello hello = new HelloImpl();
hello.sayHello();  // This will invoke the default method in interface

Enlaces útiles:

Rohit Jain
fuente
Entonces, ¿está bien si una clase implementa una interfaz y no implementa su método? En lo que respecta a Java7, lo que estoy usando, esto no está permitido.
Aniket Thakur
2
@AniketThakur. Esto no está permitido antes de Java 8. Esta función se agrega solo en Java 8. Puede evitar dar la implementación de métodos predeterminados en su clase de implementación.
Rohit Jain
1
@PawanMishra. Vea mi comentario anterior. No, no es necesario que proporcione la implementación de los métodos de interfaz predeterminados en la implementación de la clase.
Rohit Jain
1
Sin embargo, @PawanMishra puedes anularlo. No hay ninguna restricción, ya que solo necesita usar la implementación predeterminada.
Aniket Thakur
4
¡Un paso adelante que finalmente evitará ser desconcertado por la herencia múltiple!
Xtreme Biker
17

Investigué un poco y encontré lo siguiente. Espero que esto ayude.

Problema existente

Los métodos de interfaz normales se declaran como abstractos y deben definirse en la clase que implementa la interfaz. Esto 'carga' al implementador de la clase con la responsabilidad de implementar cada método declarado. Más importante aún, esto también significa que no es posible extender una interfaz después de la 'publicación'. De lo contrario, todos los implementadores tendrían que adaptar su implementación, rompiendo la compatibilidad binaria y de fuentes hacia atrás.

Solución adoptada en Java 8

Para hacer frente a estos problemas, una de las nuevas características de JDK 8 es la posibilidad de ampliar las interfaces existentes con métodos predeterminados. Los métodos predeterminados no solo se declaran, sino que también se definen en la interfaz.

Puntos importantes a tener en cuenta

  1. Los implementadores pueden optar por no implementar métodos predeterminados en la implementación de la clase.
  2. Los implementadores aún pueden anular los métodos predeterminados, al igual que los métodos de clase no finales regulares se pueden anular en las subclases.
  3. Las clases abstractas pueden incluso (re) declarar métodos predeterminados como abstractos, lo que obliga a las subclases a volver a implementar el método (a veces llamado 're-abstracción').
Aniket Thakur
fuente