¿Cuál es el propósito de la palabra clave predeterminada en Java?


95

Una interfaz en Java es similar a una clase, pero el cuerpo de una interfaz solo puede incluir métodos y finalcampos abstractos (constantes).

Recientemente, vi una pregunta, que se ve así

interface AnInterface {
    public default void myMethod() {
        System.out.println("D");
    }
}

Según la definición de interfaz, solo se permiten métodos abstractos . ¿Por qué me permite compilar el código anterior? Cual es la defaultpalabra clave?

Por otro lado, cuando estaba tratando de escribir el código siguiente, dice modifier default not allowed here

default class MyClass{

}

en vez de

class MyClass {

}

¿Alguien puede decirme el propósito de la defaultpalabra clave? ¿Solo está permitido dentro de una interfaz? ¿En qué se diferencia de default(sin modificador de acceso)?


4
Los métodos predeterminados en las interfaces se agregaron en Java 8. No es un modificador de acceso, es una implementación predeterminada.
Eran

2
@Eran, ¿no crees que la introducción del método predeterminado viola la definición de la interfaz? : s
Ravi

2
Cambió la definición de la interfaz. Esa definición ahora está desactualizada.
Louis Wasserman

2
Fueron introducidos para soportar lambdas. Los detalles de por qué se requieren están en la propuesta del hombre de paja para el Proyecto Lambda.
velocista

Respuestas:


75

Es una característica nueva en Java 8 que permite interfaceproporcionar una implementación. Descrito en Java 8 JLS-13.5.6. Declaraciones del método de interfaz que dice (en parte)

Agregar un defaultmétodo, o cambiar un método de abstracta default, no rompe la compatibilidad con binarios preexistentes, pero puede causar un IncompatibleClassChangeErrorsi un binario preexistente intenta invocar el método. Este error ocurre si el tipo calificado,, Tes un subtipo de dos interfaces, Iy J, donde ambos Iy Jdeclaran un defaultmétodo con la misma firma y resultado, y ni Ini Jes una subinterfaz del otro.

Lo nuevo en JDK 8 dice (en parte)

Los métodos predeterminados permiten agregar nuevas funciones a las interfaces de las bibliotecas y garantizan la compatibilidad binaria con el código escrito para versiones anteriores de esas interfaces.


16
Parece que ahora la interfaz y la clase abstracta son casi iguales. :)
Ravi

16
Las interfaces de @jWeaver aún no pueden tener constructores, campos, métodos privados o implementaciones de equals / hashCode / toString.
Louis Wasserman

10
@Louis Wasserman: En Java 9, pueden tener privatemétodos.
Holger

6
@Dan Pantry: los privatemétodos no son realmente parte de la interfaz, pero pueden servir como métodos auxiliares para las defaultimplementaciones o dentro de inicializadores constantes. Tenga en cuenta que ya existen en Java 8, ya que, cuando usa expresiones lambda dentro de las interfaces, privatese generan métodos sintéticos . Entonces, Java 9 le permite usar esa función para usos no sintéticos, no lambda también ...
Holger

14
@jWeaver La diferencia entre interfaces y clases se reduce al estado frente al comportamiento . Las interfaces pueden tener comportamiento, pero solo las clases pueden tener estado. (Los campos, constructores y métodos como equals / hashCode tratan sobre el estado.)
Brian Goetz

26

Se agregaron métodos predeterminados a Java 8 principalmente para admitir expresiones lambda. Los diseñadores (inteligentemente, en mi opinión) decidieron crear una sintaxis lambdas para crear implementaciones anónimas de una interfaz. Pero dado que las lambdas solo pueden implementar un solo método, estarían limitadas a interfaces con un solo método, lo que sería una restricción bastante severa. En su lugar, se agregaron métodos predeterminados para permitir el uso de interfaces más complejas.

Si necesita algo de convicción sobre la afirmación que defaultse introdujo debido a las lambdas, tenga en cuenta que la propuesta del hombre de paja del Proyecto Lambda, de Mark Reinhold, en 2009, menciona los 'Métodos de extensión' como una característica obligatoria que se agregará para admitir lambdas.

Aquí hay un ejemplo que demuestra el concepto:

interface Operator {
    int operate(int n);
    default int inverse(int n) {
        return -operate(n);
    }
}

public int applyInverse(int n, Operator operator) {
    return operator.inverse(n);
}

applyInverse(3, n -> n * n + 7);

Muy artificial, me doy cuenta, pero debería ilustrar cómo defaultadmite lambdas. Dado que inversees un valor predeterminado, una clase de implementación puede anularlo fácilmente si es necesario.


8
Esto no es realmente correcto. Las lambdas pueden ser la causa próxima, pero en realidad fueron solo la gota que colmó el vaso. La verdadera motivación fue permitir la evolución de la interfaz (permitir que las interfaces existentes evolucionaran de manera compatible para admitir un nuevo comportamiento); lambdas puede haber sido el factor que trajo esta necesidad a un primer plano, pero la característica es más general que eso.
Brian Goetz

@BrianGoetz: En mi humilde opinión, tanto Java como .NET se habrían beneficiado enormemente si los métodos predeterminados existieran desde el principio. Si se pudiera realizar alguna operación común sobre cualquier implementación de una interfaz usando solo miembros de la interfaz, pero algunas implementaciones probablemente tendrían una forma más eficiente de realizarlas, la interfaz debería definir métodos para esas operaciones y proporcionar implementaciones predeterminadas para ellas. La incapacidad de especificar implementaciones predeterminadas ha generado presión para que las interfaces omitan dichos métodos y ha hecho imposible que las agreguen más adelante.
supercat

@BrianGoetz Estoy de acuerdo en que los métodos predeterminados tienen un valor significativo más allá de las lambdas. Pero me interesaría cualquier referencia que puedas dar a ese valor más amplio que impulsa la decisión de incluirlos. Mi lectura es que las lambdas fueron la razón principal (por eso usé la palabra "principalmente" en mi respuesta).
velocista

2
Quizás este documento ayude: cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html . La sección 10 dice claramente: "El propósito de los métodos predeterminados (anteriormente conocidos como métodos de extensión virtual o métodos de defensa) es permitir que las interfaces evolucionen de manera compatible después de su publicación inicial". Los métodos compatibles con Lambda se citan luego como una ilustración de la evolución de la interfaz.
Brian Goetz

2
@Kartik ¡Estás haciendo la pregunta incorrecta! No elegimos la sintaxis basándonos en "cuál es el mínimo absoluto que se necesita para que el compilador analice el programa correctamente"; lo elegimos sobre la base de "lo que haría que la intención del programador fuera más evidente para los lectores". Diseñamos primero para los usuarios y, en segundo lugar, para los compiladores (y cuando se trata de usuarios, diseñamos primero para lectura y, en segundo lugar, para escritura)
Brian Goetz

16

Se introduce un nuevo concepto en Java 8 llamado métodos predeterminados. Los métodos predeterminados son aquellos que tienen alguna implementación predeterminada y ayudan a desarrollar las interfaces sin romper el código existente. Veamos un ejemplo:

 public interface SimpleInterface {
    public void doSomeWork();

    //A default method in the interface created using "default" keyword

    default public void doSomeOtherWork(){

    System.out.println("DoSomeOtherWork implementation in the interface");
       }
    }

 class SimpleInterfaceImpl implements SimpleInterface{

  @Override
  public void doSomeWork() {
  System.out.println("Do Some Work implementation in the class");
   }

 /*
  * Not required to override to provide an implementation
  * for doSomeOtherWork.
  */

 public static void main(String[] args) {
   SimpleInterfaceImpl simpObj = new SimpleInterfaceImpl();
   simpObj.doSomeWork();
   simpObj.doSomeOtherWork();
      }
   }

y la salida es:

Implementación Do Some Work en la clase
Implementación DoSomeOtherWork en la interfaz


16

Algo que se pasó por alto en las otras respuestas fue su papel en las anotaciones. Ya en Java 1.5, la defaultpalabra clave surgió como un medio para proporcionar un valor predeterminado para un campo de anotación.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Processor {
    String value() default "AMD";
}

Su uso estaba sobrecargado con la introducción de Java 8 para permitir que uno defina un método predeterminado en las interfaces.

Algo más que se pasó por alto: la razón por la que la declaración default class MyClass {}no es válida se debe a la forma en que se declaran las clases . No hay ninguna disposición en el idioma que permita que esa palabra clave aparezca allí. Sin embargo , aparece para declaraciones de métodos de interfaz .


3

La nueva característica de Java 8 ( Métodos predeterminados ) permite que una interfaz proporcione una implementación cuando está etiquetada con eldefault palabra clave.

Por ejemplo:

interface Test {
    default double getAvg(int avg) {
        return avg;
    }
}
class Tester implements Test{
 //compiles just fine
}

Prueba de interfaz usa la palabra clave predeterminada que permite que la interfaz proporcione una implementación predeterminada del método sin la necesidad de implementar esos métodos en las clases que usan la interfaz.

Compatibilidad con versiones anteriores: Imagine que su interfaz está implementada por cientos de clases, modificar esa interfaz obligará a todos los usuarios a implementar el método recién agregado, aunque no es esencial para muchas otras clases que implementan su interfaz.

Hechos y restricciones:

1-Solo puede declararse dentro de una interfaz y no dentro de una clase o clase abstracta.

2-Debe aportar un cuerpo

3-No se asume que sea público o abstracto como otros métodos normales usados ​​en una interfaz.


3

Los métodos predeterminados en una interfaz nos permiten agregar nuevas funcionalidades sin romper el código antiguo.

Antes de Java 8, si se agregaba un nuevo método a una interfaz, entonces todas las clases de implementación de esa interfaz estaban destinadas a anular ese nuevo método, incluso si no usaban la nueva funcionalidad.

Con Java 8, podemos agregar la implementación predeterminada para el nuevo método usando la defaultpalabra clave antes de la implementación del método.

Incluso con clases anónimas o interfaces funcionales, si vemos que algún código es reutilizable y no queremos definir la misma lógica en todas partes del código, podemos escribir implementaciones predeterminadas de esas y reutilizarlas.

Ejemplo

public interface YourInterface {
    public void doSomeWork();

    //A default method in the interface created using "default" keyword
    default public void doSomeOtherWork(){

    System.out.println("DoSomeOtherWork implementation in the interface");
       }
    }

    class SimpleInterfaceImpl implements YourInterface{

     /*
     * Not required to override to provide an implementation
     * for doSomeOtherWork.
     */
      @Override
      public void doSomeWork() {
  System.out.println("Do Some Work implementation in the class");
   }

 /*
  * Main method
  */
 public static void main(String[] args) {
   SimpleInterfaceImpl simpObj = new SimpleInterfaceImpl();
   simpObj.doSomeWork();
   simpObj.doSomeOtherWork();
      }
   }

2

Se encuentra una muy buena explicación en los tutoriales de Java ™. , parte de la explicación es la siguiente:

Considere un ejemplo que involucra a fabricantes de automóviles controlados por computadora que publican interfaces estándar de la industria que describen qué métodos pueden invocarse para operar sus automóviles. ¿Qué pasa si esos fabricantes de automóviles controlados por computadora agregan nuevas funciones, como el vuelo, a sus automóviles? Estos fabricantes necesitarían especificar nuevos métodos para permitir que otras empresas (como los fabricantes de instrumentos de guía electrónica) adapten su software a los coches voladores. ¿Dónde declararían estos fabricantes de automóviles estos nuevos métodos relacionados con los vuelos? Si los agregan a sus interfaces originales, los programadores que hayan implementado esas interfaces tendrían que reescribir sus implementaciones. Si los agregan como métodos estáticos, los programadores los considerarían como métodos de utilidad, no como métodos básicos esenciales.

Los métodos predeterminados le permiten agregar nuevas funciones a las interfaces de sus bibliotecas y garantizar la compatibilidad binaria con el código escrito para versiones anteriores de esas interfaces.


1

Los métodos predeterminados le permiten agregar nuevas funciones a las interfaces de sus aplicaciones. También se puede utilizar para tener una herencia múltiple . Además de los métodos predeterminados, puede definir métodos estáticos en interfaces. Esto le facilita la organización de los métodos de ayuda.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.