¿Las clases abstractas de Do / can reemplazan las interfaces?

En Java, puede crear una clase abstracta que contenga solo métodos abstractos. Por otro lado, puede crear una interfaz que declare los mismos métodos. Siendo ese el caso, ¿puedes usar clases abstractas en lugar de interfaces?

No siempre:

  • una clase puede extender solo una clase
  • una clase puede implementar más de una interfaz

Sun hace una comparación más detallada:

Clases abstractas versus interfaces

A diferencia de las interfaces, las clases abstractas pueden contener campos que no son estáticos y finales, y pueden contener métodos implementados. Dichas clases abstractas son similares a las interfaces, excepto que proporcionan una implementación parcial, dejándola en subclases para completar la implementación. Si una clase abstracta contiene solo declaraciones de métodos abstractos, debe declararse como una interfaz.

Se pueden implementar múltiples interfaces por clases en cualquier parte de la jerarquía de clases, independientemente de si están relacionadas entre sí de alguna manera. Piense en Comparable o Cloneable, por ejemplo.

En comparación, las clases abstractas se subclasan más comúnmente para compartir piezas de implementación. Una clase abstracta única se subclasifica por clases similares que tienen mucho en común (las partes implementadas de la clase abstracta), pero también tienen algunas diferencias (los métodos abstractos).

En algunos casos, puede usar una clase abstracta en lugar de una interfaz. Sin embargo, casi nunca es una buena idea hacerlo. En general, debes usar la regla:

  1. Las interfaces especifican el comportamiento.
  2. Las clases abstractas especifican la implementación.

El otro “problema” con el uso de clases abstractas es que ya no puede implementar mixins, es decir, puede implementar múltiples interfaces, sin embargo, solo puede extender una clase abstracta.

Un punto que falta en las respuestas aquí es la idea de quién implementará la interfaz.

Si su componente desea devolver instancias de tipos abstractos a sus interlocutores, donde los tipos concretos están definidos internamente y ocultos a las personas que llaman, utilice una interfaz . Por el contrario, si su componente consume o acepta instancias de tipos abstractos que sus interlocutores deben implementar, las clases abstractas suelen ser una mejor opción.

Anticipar la evolución y mantener la compatibilidad binaria da un puntaje a las escalas aquí. Con una clase abstracta, puede agregar métodos y, si proporciona una implementación base, las implementaciones existentes de la clase abstracta continuarán funcionando bien. Con una interfaz, agregar un método rompe la compatibilidad binaria, ya que ninguna implementación existente podría continuar comstackndo correctamente sin cambiar para definir el nuevo método.

El proyecto Apache Cactus tiene una buena discusión sobre cómo resolver estas obligaciones.

Para responder a su pregunta, sí, podría usar una clase abstracta (sin implementación) en lugar de una interfaz, pero consideraría esta mala práctica:

  • Has agotado tu “one-shot” en herencia (sin obtener ningún beneficio).
  • No puede heredar de múltiples clases abstractas, pero puede implementar múltiples interfaces.

Recomendaría el uso de clases abstractas más en situaciones en las que desee proporcionar una implementación parcial de una clase, posiblemente delegando algún comportamiento a implementaciones concretas de subclases.

  • Una clase en Java puede heredar de múltiples interfaces, pero solo de una clase abstracta.

  • Una interfaz no puede definir ningún código, en una clase abstracta, puede definir código (es decir, comportamiento predeterminado de los métodos)

Las clases abstractas y las interfaces son complementarias.

Por ejemplo, al crear una API, deseará presentar interfaces para el cliente, de modo que siempre pueda cambiar por completo la implementación, mientras que no tenga que cambiar su código y el usuario no confíe en la implementación cuando construya usando su API, sino solo en contratos de métodos.

Luego, tendrá clases abstractas implementando parcialmente estas interfaces, para

  • compartir un código común, que podría usarse en todas (o casi todas) las implementaciones para la interfaz, lo cual es obvio
  • proporcionar un comportamiento predeterminado que podría ser anulado en implementaciones ‘reales’, por ejemplo, un método toString () utilizando métodos de interfaces para crear una representación textual de la implementación
  • preservar la compatibilidad de implementaciones después de cambios de interfaz, por ejemplo cuando agrega un nuevo método en su interfaz, también agrega una implementación predeterminada en la clase abstracta para que las implementaciones (por ejemplo, las realizadas por el usuario) que extienden la clase abstracta sigan funcionando sin cambios

Las interfaces son mucho más limpias y livianas. Las clases abstractas te hacen depender mucho de él ya que no puedes extender ninguna otra clase.

Eche un vistazo al interesante artículo ” Why extends is evil ” para tener una idea acerca de las diferencias entre la implementación de la interfaz y la herencia de clases (además de las obvias restricciones múltiples)

¿Cuál debería usar, clases abstractas o interfaces?

Considere usar clases abstractas si alguna de estas afirmaciones se aplica a su situación:

  • Desea compartir el código entre varias clases estrechamente relacionadas.
  • Espera que las clases que amplían su clase abstracta tengan muchos métodos o campos comunes, o que requieran modificadores de acceso que no sean públicos (como protegidos y privados).
  • Desea declarar campos no estáticos o no finales. Esto le permite definir métodos que pueden acceder y modificar el estado del objeto al que pertenecen.

Considere usar interfaces si cualquiera de estas afirmaciones se aplica a su situación:

  • Esperas que las clases no relacionadas implementen tu interfaz. Por ejemplo, las interfaces Comparable y Cloneable son implementadas por muchas clases no relacionadas.
  • Desea especificar el comportamiento de un tipo de datos particular, pero no le preocupa quién implementa su comportamiento.
  • Desea aprovechar la herencia múltiple de tipo.

Consulte el enlace de documentación de Oracle para más detalles

Las clases abstractas son la implementación parcial de Abstracción, mientras que las interfaces son la implementación completa de Abstraction.Means en las clases abstractas, podemos poner la statement de métodos y el cuerpo del método. No podemos crear un objeto de clases abstractas (asociación) y reutilizar la clase por herencia (no por asociación). Por defecto en las interfaces, todas las variables declaradas son estáticas y todos los métodos son públicos.

Por ejemplo: en JDK hay solo unas pocas clases abstractas y HttpServlet es una de ellas que se usa en Servlet. Por lo tanto, no podemos crear objetos de HttpServlet y solo se pueden usar por herencia.

El uso principal de la interfaz es cuando crea la referencia de la interfaz y llama al método de clase particular que se resuelve en el tiempo de ejecución. Por lo tanto, siempre es mejor idea crear una referencia de interfaz para llamar al método.

Las interfaces solo pueden contener un método abstracto, también las interfaces pueden implementar múltiples interfaces para cualquier clase. Pero un resumen contiene métodos abstractos y no abstractos, y los métodos abstractos no pueden extenderse a más de una clase.