JavaRush /Blog Java /Random-ES /Pausa para el café #140. Clases abstractas e interfaces e...

Pausa para el café #140. Clases abstractas e interfaces en Java.

Publicado en el grupo Random-ES
Fuente: InfoWorld Hoy aprenderá en qué casos un desarrollador debe utilizar una clase abstracta y en qué casos una interfaz. También identificaremos las diferencias entre estos elementos del lenguaje Java y cómo utilizarlos en los programas. Pausa para el café #140.  Clases abstractas e interfaces en Java - 1Las clases e interfaces abstractas son bastante comunes en el código Java e incluso en el propio Java Development Kit (JDK). Cada uno de estos elementos tiene un propósito diferente:
  • Una interfaz es una construcción en el lenguaje Java que ayuda a implementar métodos abstractos y constantes estáticas.
  • Las clases abstractas son similares a las clases regulares, excepto que pueden incluir métodos abstractos, es decir, métodos sin cuerpo. No se pueden crear clases abstractas.
Muchos desarrolladores piensan que las interfaces y las clases abstractas son similares, pero en realidad esto no es del todo cierto. Veamos las principales diferencias entre ellos.

¿Qué es una interfaz?

En esencia, una interfaz es un contrato, por lo que depende de la implementación para definir el propósito de su creación. La interfaz no puede usar variables de instancia mutables, solo puede usar variables finales.

Cuándo usar interfaces

Las interfaces son muy útiles para separar código e implementar polimorfismo. Podemos ver esto en el JDK con la interfaz List :
public interface List<E> extends Collection<E> {

    int size();
    boolean isEmpty();
    boolean add(E e);
    E remove(int index);
    void clear();
}
Como probablemente habrás notado, este código, aunque breve, es bastante descriptivo. Podemos ver fácilmente la firma del método que se usará para implementar los métodos en la interfaz usando la clase concreta. La interfaz List contiene un contrato que puede ser implementado por ArrayList , Vector , LinkedList y otras clases. Para usar polimorfismo, simplemente podemos declarar el tipo de nuestra variable usando Lista y luego seleccionar cualquiera de las instancias disponibles. Aquí hay otro ejemplo:
List list = new ArrayList();
System.out.println(list.getClass());

 List list = new LinkedList();
 System.out.println(list.getClass());
La salida es:
clase java.util.ArrayList clase java.util.LinkedList
En este caso, los métodos de implementación para ArrayList , LinkedList y Vector son diferentes, lo cual es un escenario excelente para usar la interfaz. Si observa que muchas clases pertenecen a una clase principal con las mismas acciones de método pero con comportamiento diferente. En tales situaciones, se recomienda utilizar la interfaz. A continuación, veamos varias opciones para usar interfaces.

Anulación del método de interfaz

Como ya sabemos, una interfaz es una especie de contrato que debe ser implementado por una clase concreta. Los métodos de interfaz son implícitamente abstractos y requieren una implementación concreta de la clase. He aquí un ejemplo:
public class OverridingDemo {
  public static void main(String[] args) {
    Challenger challenger = new JavaChallenger();
    challenger.doChallenge();
  }
}

interface Challenger {
  void doChallenge();
}

class JavaChallenger implements Challenger {
  @Override
  public void doChallenge() {
    System.out.println("Challenge done!");
  }
}
Conclusión:
¡Desafío hecho!
Tenga en cuenta que los métodos de interfaz son implícitamente abstractos. Esto significa que no necesitamos declararlos explícitamente abstractos.

Variables constantes

Otra regla a recordar es que una interfaz sólo puede contener variables constantes. He aquí un ejemplo:
public class Challenger {

  int number = 7;
  String name = "Java Challenger";

}
Aquí ambas variables son implícitas finales y estáticas . Esto significa que son constantes, independientes de la instancia y no se pueden cambiar. Ahora intentaremos cambiar las variables en la interfaz Challenger , digamos así:
Challenger.number = 8;
Challenger.name = "Another Challenger";
Esto provocará un error de compilación:
No se puede asignar un valor a la variable final 'número' No se puede asignar un valor a la variable final 'nombre'

Métodos predeterminados

Cuando se introdujeron los métodos predeterminados en Java 8, algunos desarrolladores pensaron que serían lo mismo que las clases abstractas. Sin embargo, esto no es cierto porque las interfaces no pueden tener estado. Un método predeterminado puede tener una implementación, pero los métodos abstractos no. Los métodos predeterminados son el resultado de innovaciones con expresiones y flujos lambda, pero debemos usarlos con cuidado. El método en el JDK que utiliza el método predeterminado es forEach() , que forma parte de la interfaz Iterable . En lugar de copiar el código en cada implementación Iterable , simplemente podemos reutilizar el método forEach :
default void forEach(Consumer<? super T> action) {
  // Code implementation here...
Cualquier implementación de Iterable puede utilizar el método forEach() sin necesidad de implementar un nuevo método. Luego podemos reutilizar el código con el método predeterminado. Creemos nuestro propio método predeterminado:
public class DefaultMethodExample {

  public static void main(String[] args) {
    Challenger challenger = new JavaChallenger();
    challenger.doChallenge();
  }

}

class JavaChallenger implements Challenger { }

interface Challenger {

  default void doChallenge() {
    System.out.println("Challenger doing a challenge!");
  }
}
Resultado:
¡Retador haciendo un desafío!
Con respecto a los métodos predeterminados, es importante tener en cuenta que es necesario implementar cada uno de ellos. El método predeterminado no puede ser estático. Ahora pasemos a las clases abstractas.

La esencia de una clase abstracta.

Las clases abstractas pueden tener estado con variables de instancia. Esto significa que la variable de instancia se puede utilizar y modificar. He aquí un ejemplo:
public abstract class AbstractClassMutation {

  private String name = "challenger";

  public static void main(String[] args) {
    AbstractClassMutation abstractClassMutation = new AbstractClassImpl();
    abstractClassMutation.name = "mutated challenger";
    System.out.println(abstractClassMutation.name);
  }

}

class AbstractClassImpl extends AbstractClassMutation { }
Conclusión:
retador mutado

Métodos abstractos en clases abstractas.

Al igual que las interfaces, las clases abstractas pueden tener métodos abstractos. Un método abstracto es un método sin cuerpo. A diferencia de las interfaces, los métodos abstractos en clases abstractas deben declararse explícitamente abstractos. Aquí hay un ejemplo:
public abstract class AbstractMethods {

  abstract void doSomething();

}
Y aquí hay un intento de declarar un método sin implementación y sin la palabra clave abstracta :
public abstract class AbstractMethods {
   void doSomethingElse();
}
Desafortunadamente, resulta en un error de compilación:
Falta el cuerpo del método o declarar resumen

Cuándo usar clases abstractas

Se recomienda una clase abstracta cuando necesite implementar un estado mutable. Por ejemplo, Java Collections Framework incluye una clase AbstractList que utiliza el estado de las variables. En los casos en los que no es necesario mantener el estado de la clase, normalmente es mejor utilizar una interfaz.

Diferencias entre clases abstractas e interfaces.

Desde una perspectiva de programación orientada a objetos, la principal diferencia entre una interfaz y una clase abstracta es que una interfaz no puede tener estado, mientras que una clase abstracta puede tener estado con variables de instancia. Otra diferencia clave es que las clases pueden implementar más de una interfaz, pero sólo pueden extender una clase abstracta. Esta solución se basa en el hecho de que la herencia múltiple (extender más de una clase) puede provocar un bloqueo del código. Los desarrolladores del lenguaje Java decidieron evitar esto. Otra diferencia es que las interfaces pueden implementarse mediante clases o ampliarse mediante interfaces, pero las clases solo pueden ampliarse. Es importante tener en cuenta que las expresiones lambda solo se pueden usar con una interfaz funcional (es decir, una interfaz con un solo método), mientras que las clases abstractas con un solo método abstracto no pueden usar expresiones lambda. Aquí hay algunas diferencias más entre clases e interfaces abstractas. Interfaz:
  • Solo puede tener variables estáticas finales. Una interfaz nunca puede cambiar su propio estado.
  • Una clase puede implementar múltiples interfaces.
  • Se puede implementar usando la palabra clave implements. Una interfaz puede ampliar otra interfaz.
  • Los métodos solo pueden utilizar campos finales estáticos, parámetros o variables locales.
  • Sólo las interfaces funcionales pueden utilizar la función lambda en Java.
  • No puede tener un constructor.
  • Puede tener métodos abstractos.
  • Puede tener métodos predeterminados y estáticos (introducidos en Java 8).
  • Puede tener métodos privados con implementación (introducido en Java 9).
Clases abstractas:
  • Puede tener cualquier instancia o variable estática, mutable o inmutable.
  • Una clase sólo puede extender una clase abstracta.
  • Puede tener una instancia de campos, parámetros o variables locales mutables.
  • Las clases abstractas con un solo método abstracto no pueden usar expresiones lambda.
  • Puede tener un constructor.
  • Puede tener cualquier método.
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION