¿Por qué hay un método predeterminado?
Java 8 viene. Como se mencionó anteriormente, hemos discutido mucho sobre este tema antes, pero la expresión de Lambdas no es el único cambio de reglas de juego en Java 8.
Supongamos que Java 8 ha sido lanzado y contiene lambda. Ahora planea usar Lambda.
List <?> List = ... list.faceach (...);
La definición de foreach no se puede encontrar en java.util.list o java.util.collection. Por lo general, es una solución para agregar nuevos métodos e implementación a las interfaces relevantes en JDK. Sin embargo, para la versión de la versión, es imposible agregar un nuevo método a la interfaz sin afecta la implementación existente.
Por lo tanto, si la lambda se usa en Java 8, no es posible usarse para la biblioteca de colección debido a la compatibilidad hacia adelante.
Por las razones anteriores, se introdujo un nuevo concepto. El método de extensión virtual, que generalmente es el método de defensa, ahora se puede agregar a la interfaz, de modo que se pueda proporcionar la implementación predeterminada del comportamiento de la declaración.
En pocas palabras, la interfaz Java ahora puede implementar el método. La ventaja del método predeterminado es que puede agregar un nuevo método predeterminado a la interfaz sin destruir la implementación de la interfaz.
En mi opinión, este no es el tipo de característica de Java que se usará todos los días, pero definitivamente puede usar lambda para usar lambda de forma natural.
El ejemplo más simple
Veamos el ejemplo más simple: una interfaz A, la clase Clazz implementa la interfaz A.
Interfaz pública a {Void predeterminado foo () {system.out.println ("llamar a a.foo ()");} public class clase A {}El código se puede compilar, incluso si la clase Clazz no implementa el método foo (). La implementación predeterminada del método foo () se proporciona en la interfaz A.
Código del cliente usando este ejemplo:
Clazz Clazz = New Clazz ();
Herencia múltiple?
Hay una pregunta común: las personas se preguntarán cuando escuchan las nuevas características del método predeterminado "" Si una clase implementa dos interfaces, y ambas interfaces definen el método predeterminado con la misma firma. con ejemplos anteriores:
Interfaz pública a {Void predeterminado foo () {System.out.println ("llamar a a.foo ()");Este código no puede compilar las siguientes razones:
Java: Clase Clazz de los tipos A a B a Foo () hereda el valor predeterminado no relacionado
Para reparar esto, en Clazz, tenemos que resolver manualmente el método de reescribir el conflicto:
Public Class Clazz implementos A, B {public void foo () {}}} Pero, ¿qué debemos hacer si queremos llamar al método de implementación predeterminado desde la interfaz A, en lugar de implementar nuestro propio método? Esto es posible, cita el foo () en a, como se muestra a continuación:
Public Class Clazz implementos A, B {public void foo () {a.super.foo ();}}} Ahora no puedo estar muy convencido de que me gusta esta solución final. Tal vez sea más conciso que la realización del método predeterminado en la firma, como se declara en el borrador de primera mano de la especificación del método predeterminado:
Public Class Clazz Implementos A, B {public void foo () predeterminado a.foo;}Pero esto cambia la gramática, ¿no? Si la interfaz A y la interfaz B definen muchos métodos predeterminados que entran en conflicto entre sí, ¿y estoy dispuesto a usar el método predeterminado de toda la interfaz A para resolver el conflicto? En la actualidad, tengo que resolver el conflicto uno tras otro para reescribir cada par de conflictos. Esto puede requerir mucho trabajo y escribir una gran cantidad de código de plantilla.
Calculo que el método para resolver el conflicto requiere muchas discusiones, pero parece que el creador decide aceptar el desastre inevitable.
Ejemplo real
Los ejemplos reales del método predeterminado se pueden encontrar en la bolsa temprana de JDK8. Volver al ejemplo del método de colección de la colección, podemos encontrar que en la interfaz java.lang.iterable, su implementación predeterminada es la siguiente:
@FunctionalInterfacePublic Interface ITerable <T> {ITERATOR <T> ITERATOR (); Foreach utiliza un parámetro de java.util.function.consumer type de interfaz de función, que nos permite pasar una expresión de lambda o una referencia de método, como sigue:
List <?> List = ... list.faceach (System.out :: println);
Llamada de método
Echemos un vistazo a cómo se llama realmente el método predeterminado. Si no está familiarizado con este problema, puede estar interesado en leer Rebel Labs sobre Bytes Java.
Desde la perspectiva del código del cliente, el método predeterminado es solo un método virtual común. Por lo tanto, el nombre debe ser un método de extensión virtual. Por lo tanto, para un ejemplo simple del método predeterminado como interfaz, el código del cliente llamará automáticamente la interfaz en el lugar donde se llama al método predeterminado.
A clazz = new Clazz ();
Si se ha resuelto el conflicto del método predeterminado, cuando modificamos el método predeterminado y especificamos una de las interfaces, Invokespecial especificará la implementación de qué implementación de la interfaz de la llamada específica.
Public Class Clazz Implements A, B {public void foo () {a.super.foo (); La siguiente es la salida de Javap:
public void foo ();
Como puede ver: las instrucciones Invokespecial se utilizan para llamar al método de interfaz foo (). Desde la perspectiva del Bytecode, esto sigue siendo algo nuevo, porque antes de que solo pueda llamar al método señalando a una clase (padre) en lugar de un súper ese punto a una interfaz.
por fin…
El método predeterminado es el suplemento interesante del lenguaje Java. El objetivo principal de la expresión predeterminada es evolucionar la interfaz JDK estándar, y cuando finalmente comenzamos a usar la expresión Lambdas de Java 8, nos proporcionamos una experiencia de transición sin problemas. Quién sabe, tal vez veremos más métodos predeterminados en el diseño de la API en el futuro.