Diferencia entre la clase Abstact y la interfaz
- Clases abstractas versus interfaces en Java 8
- Diferencia conceptual:
Métodos predeterminados de interfaz en Java 8
- ¿Qué es el método predeterminado?
- Error de compilación del método ForEach resuelto con el método predeterminado
- Método predeterminado y problemas de ambigüedad de herencia múltiple
- Puntos importantes sobre los métodos predeterminados de la interfaz de Java:
Método estático de interfaz Java
- Método estático de interfaz Java, ejemplo de código, método estático frente a método predeterminado
- Puntos importantes sobre el método estático de la interfaz de Java:
Interfaces funcionales Java
Clases abstractas versus interfaces en Java 8
Los cambios en la interfaz de Java 8 incluyen métodos estáticos y métodos predeterminados en las interfaces. Antes de Java 8, solo podíamos tener declaraciones de método en las interfaces. Pero desde Java 8, podemos tener métodos predeterminados y métodos estáticos en las interfaces.
Después de introducir el Método predeterminado, parece que las interfaces y las clases abstractas son las mismas. Sin embargo, siguen siendo un concepto diferente en Java 8.
La clase abstracta puede definir constructor. Están más estructurados y pueden tener un estado asociado con ellos. Por el contrario, el método predeterminado solo se puede implementar en términos de invocar otros métodos de interfaz, sin referencia al estado de una implementación particular. Por lo tanto, ambos se usan para diferentes propósitos y elegir entre dos realmente depende del contexto del escenario.
Diferencia conceptual:
Las clases abstractas son válidas para implementaciones esqueléticas (es decir, parciales) de interfaces, pero no deberían existir sin una interfaz coincidente.
Entonces, cuando las clases abstractas se reducen efectivamente para que sean de baja visibilidad, las implementaciones esqueléticas de interfaces, ¿pueden los métodos predeterminados eliminar esto también? Decididamente: ¡No! La implementación de interfaces casi siempre requiere algunas o todas esas herramientas de construcción de clases de las que carecen los métodos predeterminados. Y si alguna interfaz no lo hace, es claramente un caso especial, que no debería llevarlo por mal camino.
Métodos predeterminados de interfaz en Java 8
Java 8 presenta la nueva característica " Método predeterminado " o (Métodos de defensa), que permite al desarrollador agregar nuevos métodos a las Interfaces sin interrumpir la implementación existente de estas Interfaces. Proporciona flexibilidad para permitir que la interfaz defina la implementación que se usará por defecto en la situación en la que una clase concreta no puede proporcionar una implementación para ese método.
Consideremos un pequeño ejemplo para entender cómo funciona:
public interface OldInterface {
public void existingMethod();
default public void newDefaultMethod() {
System.out.println("New default method"
+ " is added in interface");
}
}
La siguiente clase se compilará correctamente en Java JDK 8,
public class OldInterfaceImpl implements OldInterface {
public void existingMethod() {
// existing implementation is here…
}
}
Si crea una instancia de OldInterfaceImpl:
OldInterfaceImpl obj = new OldInterfaceImpl ();
// print “New default method add in interface”
obj.newDefaultMethod();
Los métodos predeterminados nunca son finales, no se pueden sincronizar y no pueden anular los métodos de Object. Siempre son públicos, lo que limita severamente la capacidad de escribir métodos cortos y reutilizables.
Los métodos predeterminados se pueden proporcionar a una interfaz sin afectar las clases de implementación, ya que incluye una implementación. Si cada método agregado en una interfaz definida con implementación no afecta a ninguna clase de implementación. Una clase implementadora puede anular la implementación predeterminada proporcionada por la interfaz.
Los métodos predeterminados permiten agregar nuevas funciones a las interfaces existentes sin interrumpir la implementación anterior de estas interfaces.
Cuando ampliamos una interfaz que contiene un método predeterminado, podemos realizar lo siguiente,
- No anular el método predeterminado y heredará el método predeterminado.
- Anule el método predeterminado similar a otros métodos que anulamos en la subclase.
- Redeclare el método predeterminado como abstracto, lo que obliga a la subclase a anularlo.
Error de compilación del método ForEach resuelto con el método predeterminado
Para Java 8, las colecciones JDK se han extendido y cada método se agrega a toda la colección (que funciona junto con lambdas). De manera convencional, el código se ve a continuación,
public interface Iterable<T> {
public void forEach(Consumer<? super T> consumer);
}
Dado que este resultado cada clase de implementación con errores de compilación, por lo tanto, se agrega un método predeterminado con una implementación requerida para que la implementación existente no deba cambiarse.
La interfaz Iterable con el método predeterminado está a continuación,
public interface Iterable<T> {
public default void forEach(Consumer
<? super T> consumer) {
for (T t : this) {
consumer.accept(t);
}
}
}
Se ha utilizado el mismo mecanismo para agregar Stream en la interfaz JDK sin romper las clases de implementación.
Método predeterminado y problemas de ambigüedad de herencia múltiple
Dado que Java Class puede implementar múltiples interfaces y cada interfaz puede definir un método predeterminado con la misma firma de método, por lo tanto, los métodos heredados pueden entrar en conflicto entre sí.
Considere el siguiente ejemplo,
public interface InterfaceA {
default void defaultMethod(){
System.out.println("Interface A default method");
}
}
public interface InterfaceB {
default void defaultMethod(){
System.out.println("Interface B default method");
}
}
public class Impl implements InterfaceA, InterfaceB {
}
El código anterior no se compilará con el siguiente error,
java: class Impl hereda valores predeterminados no relacionados para defaultMethod () de los tipos InterfaceA e InterfaceB
Para arreglar esta clase, necesitamos proporcionar la implementación del método predeterminado:
public class Impl implements InterfaceA, InterfaceB {
public void defaultMethod(){
}
}
Además, si queremos invocar la implementación predeterminada proporcionada por cualquiera de las super interfaces en lugar de nuestra propia implementación, podemos hacerlo de la siguiente manera,
public class Impl implements InterfaceA, InterfaceB {
public void defaultMethod(){
// existing code here..
InterfaceA.super.defaultMethod();
}
}
Podemos elegir cualquier implementación predeterminada o ambas como parte de nuestro nuevo método.
Puntos importantes sobre los métodos predeterminados de la interfaz de Java:
- Los métodos predeterminados de la interfaz Java nos ayudarán a extender las interfaces sin tener miedo de romper las clases de implementación.
- Los métodos predeterminados de la interfaz Java reducen las diferencias entre las interfaces y las clases abstractas.
- Los métodos predeterminados de la interfaz Java 8 nos ayudarán a evitar las clases de utilidad, como todos los métodos de la clase Colecciones que se pueden proporcionar en las interfaces en sí.
- Los métodos predeterminados de la interfaz Java nos ayudarán a eliminar las clases de implementación base, podemos proporcionar una implementación predeterminada y las clases de implementación pueden elegir cuál anular.
- Una de las principales razones para introducir métodos predeterminados en las interfaces es mejorar la API de colecciones en Java 8 para admitir expresiones lambda.
- Si alguna clase en la jerarquía tiene un método con la misma firma, los métodos predeterminados se vuelven irrelevantes. Un método predeterminado no puede anular un método de java.lang.Object. El razonamiento es muy simple, es porque Object es la clase base para todas las clases de Java. Entonces, incluso si tenemos métodos de clase Object definidos como métodos predeterminados en las interfaces, será inútil porque siempre se usará el método de clase Object. Es por eso que para evitar confusiones, no podemos tener métodos predeterminados que anulen los métodos de la clase Object.
- Los métodos predeterminados de la interfaz Java también se denominan métodos de defensa o métodos de extensión virtual.
Enlace de recursos:
- Interfaz con métodos predeterminados vs clase abstracta en Java 8
- Clase abstracta versus interfaz en la era JDK 8
- Evolución de la interfaz a través de métodos de extensión virtual
Método estático de interfaz Java
Método estático de interfaz Java, ejemplo de código, método estático frente a método predeterminado
El método estático de la interfaz Java es similar al método predeterminado, excepto que no podemos anularlos en las clases de implementación. Esta característica nos ayuda a evitar resultados no deseados en caso de una implementación deficiente en las clases de implementación. Veamos esto con un simple ejemplo.
public interface MyData {
default void print(String str) {
if (!isNull(str))
System.out.println("MyData Print::" + str);
}
static boolean isNull(String str) {
System.out.println("Interface Null Check");
return str == null ? true : "".equals(str) ? true : false;
}
}
Ahora veamos una clase de implementación que tiene el método isNull () con una implementación deficiente.
public class MyDataImpl implements MyData {
public boolean isNull(String str) {
System.out.println("Impl Null Check");
return str == null ? true : false;
}
public static void main(String args[]){
MyDataImpl obj = new MyDataImpl();
obj.print("");
obj.isNull("abc");
}
}
Tenga en cuenta que isNull (String str) es un método de clase simple, no anula el método de interfaz. Por ejemplo, si agregaremos la anotación @Override al método isNull (), se producirá un error del compilador.
Ahora, cuando ejecutaremos la aplicación, obtendremos el siguiente resultado.
Comprobación nula de interfaz
Impl Cheque nulo
Si hacemos que el método de interfaz sea estático a predeterminado, obtendremos el siguiente resultado.
Impl Cheque nulo
MyData Print ::
Impl Cheque nulo
El método estático de la interfaz Java es visible solo para los métodos de interfaz, si eliminamos el método isNull () de la clase MyDataImpl, no podremos usarlo para el objeto MyDataImpl. Sin embargo, como otros métodos estáticos, podemos usar métodos estáticos de interfaz usando el nombre de clase. Por ejemplo, una declaración válida será:
boolean result = MyData.isNull("abc");
Puntos importantes sobre el método estático de la interfaz de Java:
- El método estático de la interfaz Java es parte de la interfaz, no podemos usarlo para objetos de clase de implementación.
- Los métodos estáticos de la interfaz Java son buenos para proporcionar métodos de utilidad, por ejemplo, verificación nula, clasificación de colecciones, etc.
- El método estático de la interfaz Java nos ayuda a proporcionar seguridad al no permitir que las clases de implementación los anulen.
- No podemos definir el método estático de interfaz para los métodos de clase Object, obtendremos un error del compilador como "Este método estático no puede ocultar el método de instancia de Object". Esto se debe a que no está permitido en Java, ya que Object es la clase base para todas las clases y no podemos tener un método estático de nivel de clase y otro método de instancia con la misma firma.
- Podemos usar métodos estáticos de la interfaz de Java para eliminar clases de utilidad como Colecciones y mover todos sus métodos estáticos a la interfaz correspondiente, que sería fácil de encontrar y usar.
Interfaces funcionales Java
Antes de concluir la publicación, me gustaría proporcionar una breve introducción a las interfaces funcionales. Una interfaz con exactamente un método abstracto se conoce como interfaz funcional.
Se @FunctionalInterface
ha introducido una nueva anotación para marcar una interfaz como Interfaz funcional. @FunctionalInterface
La anotación es una facilidad para evitar la adición accidental de métodos abstractos en las interfaces funcionales. Es opcional pero es una buena práctica usarlo.
Las interfaces funcionales son una característica muy esperada y muy buscada de Java 8 porque nos permite usar expresiones lambda para instanciarlas. Se agrega un nuevo paquete java.util.function con un montón de interfaces funcionales para proporcionar tipos de destino para expresiones lambda y referencias de métodos. Examinaremos interfaces funcionales y expresiones lambda en las próximas publicaciones.
Ubicación del recurso:
- Cambios en la interfaz de Java 8: método estático, método predeterminado