resueltos poo interfaces ejercicios ejemplo clases clase abstractas abstracta java oop inheritance interface abstract-class

java - poo - ¿Cómo debería haber explicado la diferencia entre una interfaz y una clase abstracta?



ejercicios resueltos de clases abstractas en java (30)

En una de mis entrevistas, me pidieron que explicara la diferencia entre una interfaz y una clase abstracta .

Aquí está mi respuesta:

Los métodos de una interfaz Java son implícitamente abstractos y no pueden tener implementaciones. Una clase abstracta de Java puede tener métodos de instancia que implementa un comportamiento predeterminado.

Las variables declaradas en una interfaz Java son, por defecto, finales. Una clase abstracta puede contener variables no finales.

Los miembros de una interfaz Java son públicos por defecto. Una clase abstracta de Java puede tener los sabores habituales de los miembros de la clase como privado, protegido, etc.

Una interfaz de Java debe implementarse utilizando palabras clave "implementos"; Una clase abstracta de Java debe extenderse usando la palabra clave "extiende".

Una interfaz puede extender solo otra interfaz Java, una clase abstracta puede extender otra clase Java e implementar múltiples interfaces Java.

Una clase de Java puede implementar múltiples interfaces pero puede extender solo una clase abstracta.

Sin embargo, el entrevistador no estaba satisfecho, y me dijo que esta descripción representaba " conocimiento de libro ".

Me pidió una respuesta más práctica, explicando cuándo elegiría una clase abstracta sobre una interfaz, usando ejemplos prácticos .

¿Qué hice mal?


Diferencia entre la clase Abstact y la interfaz

  1. Clases abstractas versus interfaces en Java 8
  2. Diferencia Conceptual:

Métodos predeterminados de interfaz en Java 8

  1. ¿Qué es el método predeterminado?
  2. Error de compilación del método ForEach resuelto usando el método predeterminado
  3. Método predeterminado y problemas de ambigüedad de herencia múltiple
  4. Puntos importantes sobre los métodos por defecto de la interfaz de Java:

Método estático de la interfaz Java

  1. Método estático de la interfaz de Java, ejemplo de código, método estático vs método predeterminado
  2. Puntos importantes sobre el método estático de la interfaz java:

Interfaces funcionales de 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étodos 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 iguales. Sin embargo, todavía son conceptos diferentes en Java 8.

La clase abstracta puede definir al constructor. Son más estructurados y pueden tener un estado asociado con ellos. En contraste, el método predeterminado solo se puede implementar en los términos de invocar otros métodos de interfaz, sin referencia al estado de una implementación en particular. Por lo tanto, el uso para diferentes propósitos y la elección 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 de manera efectiva para ser de baja visibilidad, las implementaciones esqueléticas de las interfaces, ¿pueden los métodos predeterminados eliminar esto también? Decididamente: ¡No! La implementación de interfaces casi siempre requiere algunas o todas las herramientas de creació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 romper la implementación existente de esta interfaz. Proporciona flexibilidad para permitir que la interfaz defina la implementación que se utilizará como predeterminada 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á con éxito en Java JDK 8,

public class OldInterfaceImpl implements OldInterface {     public void existingMethod() {      // existing implementation is here…     } }

Si creas una instancia de OldInterfaceImpl:

OldInterfaceImpl obj = new OldInterfaceImpl (); // print “New default method add in interface” obj.newDefaultMethod(); 

Método predeterminado:

Los métodos predeterminados nunca son definitivos, no se pueden sincronizar y no se pueden anular los métodos de Object. Siempre son públicos, lo que limita gravemente la capacidad de escribir métodos cortos y reutilizables.

Los métodos predeterminados se pueden proporcionar a una Interfaz sin afectar a las Clases de implementación, ya que incluye una implementación. Si cada método agregado en una Interfaz definida con implementación, no se ve afectada la Clase de implementación. Una Clase de implementación puede anular la implementación predeterminada proporcionada por la Interfaz.

Los métodos predeterminados permiten agregar una nueva funcionalidad a las interfaces existentes sin romper la implementación anterior de estas interfaces.

Cuando extendemos una interfaz que contiene un método predeterminado, podemos realizar lo siguiente:

  1. No anulará el método predeterminado y heredará el método predeterminado.
  2. Reemplace el método predeterminado similar a otros métodos que reemplazamos en la subclase.
  3. Volver a declarar el método predeterminado como abstracto, lo que obliga a la subclase a anularlo.

Error de compilación del método ForEach resuelto usando el método predeterminado

Para Java 8, las colecciones JDK se han ampliado y el método forEach se agrega a toda la colección (que funciona en conjunto con las lambdas). Con la forma convencional, el código se ve a continuación,

public interface Iterable<T> {     public void forEach(Consumer<? super T> consumer); }

Como este resultado, cada clase de implementación con errores de compilación, por lo tanto, se agregó un método predeterminado con una implementación requerida para que la implementación existente no se modifique.

La Interfaz de Iterable con el método por defecto está debajo,

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

Como Java Class puede implementar múltiples Interfaces y cada Interfaz puede definir el 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 podrá compilarse con el siguiente error,

java: class Impl hereda valores predeterminados no relacionados para defaultMethod () de los tipos InterfaceA e InterfaceB

Para corregir 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 cualquier super interfaz 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 por defecto de la interfaz de Java:

  1. Los métodos predeterminados de la interfaz Java nos ayudarán a ampliar las interfaces sin tener el miedo de romper las clases de implementación.
  2. Los métodos predeterminados de la interfaz de Java han superado las diferencias entre interfaces y clases abstractas.
  3. Los métodos predeterminados de la interfaz de Java 8 nos ayudarán a evitar las clases de utilidad, ya que todo el método de la clase Colecciones puede proporcionarse en las propias interfaces.
  4. Los métodos predeterminados de la interfaz de Java nos ayudarán a eliminar las clases de implementación básicas, podemos proporcionar la implementación predeterminada y las clases de implementación pueden elegir cuál anular.
  5. Una de las principales razones para introducir métodos predeterminados en las interfaces es mejorar la API de colecciones en Java 8 para admitir las expresiones lambda.
  6. 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, ya que Object es la clase base para todas las clases Java. Entonces, incluso si tenemos métodos de clase de objetos definidos como métodos predeterminados en las interfaces, será inútil porque el método de la clase de objetos siempre se usará. Es por eso que para evitar confusiones, no podemos tener métodos predeterminados que estén anulando los métodos de la clase Object.
  7. Los métodos predeterminados de la interfaz Java también se conocen como Métodos de defensa o Métodos de extensión virtual.

Enlace de recursos:

  1. Interfaz con métodos predeterminados vs clase abstracta en Java 8
  2. Clase abstracta versus interfaz en la era JDK 8
  3. Evolución de la interfaz a través de métodos de extensión virtual.

Método estático de la interfaz Java

Método estático de la interfaz de Java, ejemplo de código, método estático vs 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 ejemplo simple.

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 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 reemplaza al método de interfaz. Por ejemplo, si agregaremos la anotación @Override al método isNull (), se producirá un error del compilador.

Ahora, cuando ejecutemos la aplicación, obtenemos la siguiente salida.

Interfaz Null Check

Impl Null Check

Si hacemos el método de interfaz de estático a predeterminado, obtendremos la siguiente salida.

Impl Null Check

MyData Print ::

Impl Null Check

El método estático de la interfaz Java solo es visible para los métodos de la interfaz. Si eliminamos el método isNull () de la clase MyDataImpl, no podremos usarlo para el objeto MyDataImpl. Sin embargo, al igual que otros métodos estáticos, podemos utilizar métodos estáticos de interfaz utilizando 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 java:

  1. El método estático de la interfaz Java es parte de la interfaz, no podemos usarlo para objetos de clase de implementación.
  2. Los métodos estáticos de la interfaz Java son buenos para proporcionar métodos de utilidad, por ejemplo, comprobación de nulos, clasificación de colecciones, etc.
  3. 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.
  4. No podemos definir el método de interfaz estática para los métodos de clase de Objeto, obtendremos un error del compilador como "Este método estático no puede ocultar el método de instancia de Objeto". 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.
  5. Podemos usar métodos estáticos de la interfaz de Java para eliminar clases de utilidades 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 de 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 ha introducido una nueva anotación @FunctionalInterface para marcar una interfaz como interfaz funcional. @FunctionalInterface anotación @FunctionalInterface 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 buscada y esperada 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. Analizaremos las interfaces funcionales y las expresiones lambda en las publicaciones futuras.

Ubicación del recurso:

  1. Cambios en la interfaz de Java 8 - método estático, método predeterminado

¿Su explicación parece decente, pero puede parecer que lo estaba leyendo todo de un libro de texto? : - /

Lo que más me molesta es, ¿qué tan sólido fue tu ejemplo? ¿Te molestaste en incluir casi todas las diferencias entre resumen e interfaces?

Personalmente, sugeriría este enlace: http://mindprod.com/jgloss/interfacevsabstract.html#TABLE

Para una lista exhaustiva de diferencias.

Espero que te ayude a ti ya todos los demás lectores en sus futuras entrevistas.


Hizo un buen resumen de las diferencias prácticas en el uso y la implementación, pero no dijo nada sobre la diferencia en el significado.

Una interfaz es una descripción del comportamiento que tendrá una clase implementadora. La clase implementadora asegura que tendrá estos métodos que se pueden usar en ella. Es básicamente un contrato o una promesa que la clase tiene que hacer.

Una clase abstracta es una base para diferentes subclases que comparten un comportamiento que no necesita crearse repetidamente. Las subclases deben completar el comportamiento y tener la opción de anular el comportamiento predefinido (siempre que no esté definido como final o private ).

Encontrará buenos ejemplos en el paquete java.util que incluye interfaces como List y clases abstractas como AbstractList que ya implementa la interfaz. La documentación oficial describe la AbstractList siguiente manera:

Esta clase proporciona una implementación esquelética de la interfaz de la Lista para minimizar el esfuerzo requerido para implementar esta interfaz respaldada por un almacén de datos de "acceso aleatorio" (como una matriz).


Muchos desarrolladores junior cometen el error de pensar en interfaces, clases abstractas y concretas como ligeras variaciones de la misma cosa, y eligen uno de ellos exclusivamente por razones técnicas: ¿Necesito herencia múltiple? ¿Necesito algún lugar para poner métodos comunes? ¿Necesito molestarme con algo más que una clase concreta? Esto es incorrecto, y oculto en estas preguntas es el problema principal: "Yo" . Cuando escribe un código para usted mismo, raramente piensa en otros desarrolladores presentes o futuros que trabajen en o con su código.

Interfaces y clases abstractas, aunque aparentemente similares desde un punto de vista técnico, tienen significados y propósitos completamente diferentes.

Resumen

  1. Una interfaz define un contrato que alguna implementación cumplirá para usted .

  2. Una clase abstracta proporciona un comportamiento predeterminado que su implementación puede reutilizar.

Estos dos puntos anteriores es lo que busco al entrevistar, y es un resumen lo suficientemente compacto. Siga leyendo para más detalles.

Resumen alternativo

  1. Una interfaz es para definir APIs públicas.
  2. Una clase abstracta es para uso interno y para definir SPIs.

Por ejemplo

En otras palabras: una clase concreta hace el trabajo real, de una manera muy específica. Por ejemplo, un ArrayList usa un área contigua de memoria para almacenar una lista de objetos de manera compacta que ofrece acceso aleatorio rápido, iteración y cambios en el lugar, pero es terrible en las inserciones, eliminaciones y, ocasionalmente, incluso en adiciones; Mientras tanto, una lista enlazada usa nodos de doble LinkedList para almacenar una lista de objetos, que en su lugar ofrece una iteración rápida, cambios en el lugar e inserción / eliminación / adición, pero es terrible en el acceso aleatorio. Estos dos tipos de listas están optimizados para diferentes casos de uso, y es muy importante cómo los va a utilizar. Cuando esté tratando de exprimir el rendimiento de una lista con la que está interactuando intensamente, y cuando elija el tipo de lista que le corresponda, debe elegir con cuidado cuál de ellas está creando.

Por otro lado, a los usuarios de alto nivel de una lista realmente no les importa cómo se implementa, y deben estar aislados de estos detalles. Imaginemos que Java no expuso la interfaz de la List , sino que solo tenía una clase de List concreta que en realidad es lo que LinkedList es en este momento. Todos los desarrolladores de Java habrían adaptado su código para que se ajustara a los detalles de la implementación: evitar el acceso aleatorio, agregar un caché para acelerar el acceso o simplemente volver a implementar ArrayList por su cuenta, aunque sería incompatible con todos los demás códigos que realmente funcionan con List . Eso sería terrible ... Pero ahora imagine que los maestros de Java realmente se dan cuenta de que una lista enlazada es terrible para la mayoría de los casos de uso reales, y decidió cambiar a una lista de matriz para su única clase de List disponible. Esto afectaría el rendimiento de cada programa Java en el mundo, y la gente no estaría contenta con él. Y el principal culpable es que los detalles de la implementación estaban disponibles, y los desarrolladores asumieron que esos detalles son un contrato permanente en el que pueden confiar. Por eso es importante ocultar los detalles de la implementación y solo definir un contrato abstracto. Este es el propósito de una interfaz: definir qué tipo de entrada acepta un método y qué tipo de salida se espera, sin exponer todas las agallas que podrían tentar a los programadores a modificar su código para que se ajuste a los detalles internos que podrían cambiar con cualquier actualización futura .

Una clase abstracta está en el medio entre interfaces y clases concretas. Se supone que ayuda a las implementaciones a compartir código común o aburrido. Por ejemplo, AbstractCollection proporciona implementaciones básicas para isEmpty función de que el tamaño es 0, contains como iterar y comparar, add como add repetido, etc. Esto permite que las implementaciones se centren en las partes cruciales que las diferencian: cómo almacenar y recuperar datos.

Otra perspectiva: APIs versus SPIs

Las interfaces son puertas de enlace de baja cohesión entre diferentes partes del código. Permiten que las bibliotecas existan y evolucionen sin interrumpir a cada usuario de la biblioteca cuando algo cambia internamente. Se llama interfaz de programación de aplicaciones , no clases de programación de aplicaciones. En una escala más pequeña, también permiten que múltiples desarrolladores colaboren con éxito en proyectos a gran escala, separando diferentes módulos a través de interfaces bien documentadas.

Las clases abstractas son ayudantes de alta cohesión que se utilizarán al implementar una interfaz, asumiendo algún nivel de detalles de implementación. Alternativamente, las clases abstractas se utilizan para definir SPI, interfaces de proveedor de servicios.

La diferencia entre una API y un SPI es sutil, pero importante: para una API, el enfoque está en quién lo usa , y para un SPI, el enfoque está en quién lo implementa .

Agregar métodos a una API es fácil, todos los usuarios existentes de la API seguirán compilando. Añadir métodos a un SPI es difícil, ya que cada proveedor de servicios (implementación concreta) tendrá que implementar los nuevos métodos. Si se usan interfaces para definir un SPI, un proveedor tendrá que lanzar una nueva versión cada vez que cambie el contrato de SPI. Si se usan clases abstractas en su lugar, los nuevos métodos podrían definirse en términos de métodos abstractos existentes, o como throw not implemented exception vacíos throw not implemented exception talones de throw not implemented exception , que al menos permitirán que una versión anterior de una implementación de servicio aún se compile y ejecute.

Una nota sobre Java 8 y métodos por defecto.

Aunque Java 8 introdujo métodos predeterminados para las interfaces, lo que hace que la línea entre las interfaces y las clases abstractas sea aún más confusa, no fue así para que las implementaciones puedan reutilizar el código, sino para facilitar el cambio de las interfaces que sirven como API y como SPI (o se utilizan incorrectamente para definir SPI en lugar de clases abstractas).

"Conocimiento del libro"

Los detalles técnicos proporcionados en la respuesta del OP se consideran "conocimiento del libro" porque este suele ser el enfoque utilizado en la escuela y en la mayoría de los libros de tecnología sobre un idioma: lo que es una cosa, no cómo usarlo en la práctica, especialmente en aplicaciones a gran escala .

Aquí hay una analogía: se suponía que la pregunta era:

¿Qué es mejor alquilar para la noche de graduación, un auto o una habitación de hotel?

La respuesta técnica suena como:

Bueno, en un automóvil puedes hacerlo antes, pero en una habitación de hotel puedes hacerlo más cómodamente. Por otro lado, la habitación del hotel está en un solo lugar, mientras que en el automóvil puede hacerlo en más lugares, como, digamos que puede ir al punto de vista para una buena vista, o en un autocine, o muchos otros lugares, o incluso en más de un lugar. Además, la habitación del hotel tiene una ducha.

Todo eso es cierto, pero pierde por completo los puntos de que son dos cosas completamente diferentes, y ambas pueden usarse al mismo tiempo para diferentes propósitos, y el aspecto de "hacerlo" no es lo más importante acerca de ninguna de las dos opciones. . La respuesta carece de perspectiva, muestra una forma inmadura de pensar, al tiempo que presenta correctamente los "hechos".


Nada es perfecto en este mundo. Ellos pueden haber estado esperando más de un enfoque práctico.

Pero después de su explicación, podría agregar estas líneas con un enfoque ligeramente diferente.

  1. Las interfaces son reglas (reglas porque debe darles una implementación que no puede ignorar o evitar, para que se impongan como reglas) que funciona como un documento de entendimiento común entre varios equipos en el desarrollo de software.

  2. Las interfaces dan la idea de qué se debe hacer, pero no cómo se hará. Por lo tanto, la implementación depende completamente del desarrollador al seguir las reglas dadas (significa la firma dada de los métodos).

  3. Las clases abstractas pueden contener declaraciones abstractas, implementaciones concretas o ambas.

  4. Las declaraciones abstractas son como las reglas a seguir y las implementaciones concretas son como pautas (puede usarlas tal como son o puede ignorarlas anulando y otorgando su propia implementación).

  5. Además, los métodos con la misma firma que pueden cambiar el comportamiento en un contexto diferente se proporcionan como declaraciones de interfaz como reglas para implementar en consecuencia en contextos diferentes.

Edición: Java 8 facilita la definición de métodos predeterminados y estáticos en la interfaz.

public interface SomeInterfaceOne { void usualAbstractMethod(String inputString); default void defaultMethod(String inputString){ System.out.println("Inside SomeInterfaceOne defaultMethod::"+inputString); } }

Ahora, cuando una clase implementará SomeInterface, no es obligatorio proporcionar la implementación de los métodos de interfaz predeterminados.

Si tenemos otra interfaz con los siguientes métodos:

public interface SomeInterfaceTwo { void usualAbstractMethod(String inputString); default void defaultMethod(String inputString){ System.out.println("Inside SomeInterfaceTwo defaultMethod::"+inputString); } }

Java no permite extender varias clases porque da como resultado el "Problema Diamante", donde el compilador no puede decidir qué método de superclase usar. Con los métodos predeterminados, también surgirá el problema del diamante para las interfaces. Porque si una clase está implementando tanto

SomeInterfaceOne and SomeInterfaceTwo

y no implementa el método predeterminado común, el compilador no puede decidir cuál elegir. Para evitar este problema, en java 8 es obligatorio implementar métodos predeterminados comunes de diferentes interfaces. Si alguna clase está implementando las dos interfaces anteriores, debe proporcionar implementación para el método defaultMethod (), de lo contrario el compilador generará un error de tiempo de compilación.


Te daré un ejemplo primero:

public interface LoginAuth{ public String encryptPassword(String pass); public void checkDBforUser(); }

Ahora suponga que tiene 3 bases de datos en su aplicación. Luego, cada implementación de esa base de datos debe definir los dos métodos anteriores:

public class DBMySQL implements LoginAuth{ // Needs to implement both methods } public class DBOracle implements LoginAuth{ // Needs to implement both methods } public class DBAbc implements LoginAuth{ // Needs to implement both methods }

Pero, ¿qué pasa si encryptPassword () no depende de la base de datos, y es lo mismo para cada clase? Entonces lo anterior no sería un buen enfoque.

En su lugar, considere este enfoque:

public abstract class LoginAuth{ public String encryptPassword(String pass){ // Implement the same default behavior here // that is shared by all subclasses. } // Each subclass needs to provide their own implementation of this only: public abstract void checkDBforUser(); }

Ahora, en cada clase secundaria, solo necesitamos implementar un método: el método que depende de la base de datos.

Hice mi mejor esfuerzo y espero que esto despejará tus dudas.


Una interfaz consta de variables singleton (final público estático) y métodos abstractos públicos. Normalmente preferimos utilizar una interfaz en tiempo real cuando sabemos qué hacer pero no sabemos cómo hacerlo .

Este concepto se puede entender mejor con el ejemplo:

Considere una clase de pago. El pago se puede realizar de muchas maneras, como PayPal, tarjeta de crédito, etc. Por lo tanto, normalmente tomamos Pago como nuestra interfaz que contiene un método makePayment() y CreditCard y PayPal son las dos clases de implementación.

public interface Payment { void makePayment();//by default it is a abstract method } public class PayPal implements Payment { public void makePayment() { //some logic for PayPal payment //e.g. Paypal uses username and password for payment } } public class CreditCard implements Payment { public void makePayment() { //some logic for CreditCard payment //e.g. CreditCard uses card number, date of expiry etc... } }

En el ejemplo anterior, CreditCard y PayPal son dos clases / estrategias de implementación. Una Interfaz también nos permite el concepto de herencia múltiple en Java que no se puede lograr con una clase abstracta.

Elegimos una clase abstracta cuando hay algunas características para las que sabemos qué hacer y otras características que sabemos cómo realizar .

Considere el siguiente ejemplo:

public abstract class Burger { public void packing() { //some logic for packing a burger } public abstract void price(); //price is different for different categories of burgers } public class VegBerger extends Burger { public void price() { //set price for a veg burger. } } public class NonVegBerger extends Burger { public void price() { //set price for a non-veg burger. } }

Si agregamos métodos (concretos / abstractos) en el futuro a una clase abstracta dada, entonces la clase de implementación no necesitará cambiar su código. Sin embargo, si agregamos métodos en una interfaz en el futuro, debemos agregar implementaciones a todas las clases que implementaron esa interfaz, de lo contrario se producirán errores de tiempo de compilación.

Existen otras diferencias, pero estas son las principales, que pueden haber sido las esperadas por su entrevistador. Esperemos que esto haya sido útil.


¿Qué hay de pensar de la siguiente manera:

  • Una relación entre una clase y una clase abstracta es de tipo "is-a"
  • Una relación entre una clase y una interfaz es de tipo "has-a"

Entonces, cuando tienes una clase abstracta de mamíferos, una subclase humana y una interfaz de conducción, entonces puedes decir

  • cada ser humano es un mamífero
  • cada ser humano tiene una conducción (comportamiento)

Mi sugerencia es que la frase de conocimiento del libro indica que quería escuchar la diferencia semántica entre ambos (como otros aquí ya sugeridos).


Todas sus declaraciones son válidas, excepto su primera declaración (después del lanzamiento de Java 8):

Los métodos de una interfaz Java son implícitamente abstractos y no pueden tener implementaciones

Desde la page documentación:

Una interfaz es un tipo de referencia, similar a una clase, que puede contener solo constantes, firmas de métodos, métodos predeterminados, métodos estáticos y tipos anidados

Los cuerpos de los métodos existen solo para los métodos predeterminados y los métodos estáticos.

Métodos predeterminados:

Una interfaz puede tener métodos predeterminados , pero son diferentes a los métodos abstractos en clases abstractas.

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

Cuando extiende una interfaz que contiene un método predeterminado, puede hacer lo siguiente:

  1. Sin mencionar el método predeterminado, lo que permite que su interfaz extendida herede el método predeterminado.
  2. Volver a declarar el método predeterminado, lo que lo hace abstract .
  3. Redefinir el método predeterminado, que lo anula.

Métodos estáticos:

Además de los métodos predeterminados, puede definir métodos estáticos en las interfaces. (Un método estático es un método que está asociado con la clase en la que se define en lugar de con cualquier objeto. Cada instancia de la clase comparte sus métodos estáticos).

Esto facilita la organización de métodos auxiliares en sus bibliotecas;

Código de ejemplo de la página de documentación sobre la interface con métodos static y default .

import java.time.*; public interface TimeClient { void setTime(int hour, int minute, int second); void setDate(int day, int month, int year); void setDateAndTime(int day, int month, int year, int hour, int minute, int second); LocalDateTime getLocalDateTime(); static ZoneId getZoneId (String zoneString) { try { return ZoneId.of(zoneString); } catch (DateTimeException e) { System.err.println("Invalid time zone: " + zoneString + "; using default time zone instead."); return ZoneId.systemDefault(); } } default ZonedDateTime getZonedDateTime(String zoneString) { return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString)); } }

Utilice las siguientes pautas para elegir si desea utilizar una interfaz o una clase abstracta.

Interfaz:

  1. Para definir un contrato (preferiblemente sin estado, quiero decir sin variables)
  2. Para vincular las clases no relacionadas con tiene una capacidad.
  3. Declarar constantes públicas ( estado inmutable ).

Clase abstracta:

  1. Compartir código entre varias clases estrechamente relacionadas. Establece es una relación.

  2. Compartir estado común entre clases relacionadas (el estado puede ser modificado en clases concretas)

Artículos Relacionados:

Interfaz vs clase abstracta (OO general)

Implementa vs extiende: ¿Cuándo usarlo? ¿Cual es la diferencia?

Al pasar por estos ejemplos, puedes entender que

Las clases no relacionadas pueden tener capacidades a través de la interfaz, pero las clases relacionadas cambian el comportamiento a través de la extensión de las clases base.


Cuando trato de compartir el comportamiento entre 2 clases estrechamente relacionadas, creo una clase abstracta que mantiene el comportamiento común y sirve como padre para ambas clases.

Cuando estoy tratando de definir un Tipo, una lista de métodos a los que un usuario de mi objeto puede recurrir de manera confiable, luego creo una interfaz.

Por ejemplo, nunca crearía una clase abstracta con 1 subclase concreta porque las clases abstractas son sobre el comportamiento de compartir. Pero podría muy bien crear una interfaz con una sola implementación. El usuario de mi código no sabrá que solo hay una implementación. De hecho, en una versión futura puede haber varias implementaciones, todas las cuales son subclases de una nueva clase abstracta que ni siquiera existía cuando creé la interfaz.

Eso podría haber parecido demasiado estrafalario (aunque nunca lo he visto así en ninguna parte que recuerdo). Si el entrevistador (o el OP) realmente quisiera más de mi experiencia personal en eso, habría estado listo con las anécdotas de una interfaz que ha evolucionado por necesidad y viceversa.

Una cosa más. Java 8 ahora le permite colocar el código predeterminado en una interfaz, borrando aún más la línea entre las interfaces y las clases abstractas. Pero, por lo que he visto, esa característica está sobreutilizada incluso por los creadores de las bibliotecas principales de Java. Esa característica se agregó, y con razón, para hacer posible extender una interfaz sin crear incompatibilidad binaria. Pero si está creando un Tipo completamente nuevo definiendo una interfaz, entonces la interfaz debería ser SÓLO una interfaz. Si también desea proporcionar un código común, entonces, por supuesto, haga una clase de ayuda (abstracta o concreta). No esté saturando su interfaz desde el principio con la funcionalidad que desee cambiar.


Creo que lo que el entrevistador estaba tratando de lograr era probablemente la diferencia entre la interfaz y la implementación.

La interfaz, no una interfaz de Java, sino "interfaz" en términos más generales, para un módulo de código es, básicamente, el contrato realizado con el código de cliente que utiliza la interfaz.

La implementación de un módulo de código es el código interno que hace que el módulo funcione. A menudo, puede implementar una interfaz en particular de más de una manera diferente, e incluso cambiar la implementación sin que el código del cliente sea consciente del cambio.

Una interfaz Java solo debe usarse como interfaz en el sentido genérico anterior, para definir cómo se comporta la clase en beneficio del código del cliente que utiliza la clase, sin especificar ninguna implementación. Por lo tanto, una interfaz incluye firmas de métodos (los nombres, los tipos de retorno y las listas de argumentos) para los métodos que se espera que el código del cliente llame, y en principio debería tener un montón de Javadoc para cada método que describa lo que hace ese método. La razón más convincente para usar una interfaz es si planea tener varias implementaciones diferentes de la interfaz, tal vez seleccionando una implementación dependiendo de la configuración de la implementación.

Una clase abstracta de Java, en contraste, proporciona una implementación parcial de la clase, en lugar de tener el propósito principal de especificar una interfaz. Se debe utilizar cuando varias clases comparten el código, pero también cuando se espera que las subclases proporcionen parte de la implementación. Esto permite que el código compartido aparezca en un solo lugar, la clase abstracta, al tiempo que deja claro que partes de la implementación no están presentes en la clase abstracta y se espera que las subclases las proporcionen.


De lo que entiendo y de cómo me acerco,

La interfaz es como una especificación / contrato, cualquier clase que implemente una clase de interfaz debe implementar todos los métodos definidos en la clase abstracta (excepto los métodos predeterminados (introducidos en java 8))

Mientras que yo defino un resumen de clase cuando conozco la implementación requerida para algunos métodos de la clase y algunos métodos todavía no sé cuál será la implementación (podríamos conocer la firma de función pero no la implementación) Hago esto de manera que más adelante en la parte del desarrollo, cuando sé cómo se implementarán estos métodos, puedo extender esta clase abstracta e implementar estos métodos.

Nota: no puede tener el cuerpo de la función en los métodos de interfaz a menos que el método sea estático o predeterminado.


Su respuesta está bien, pero creo que estaba buscando este tipo de respuesta:

Clase abstracta

  • La clase abstracta puede tener métodos abstractos y no abstractos.
  • La clase abstracta no admite herencia múltiple.
  • La clase abstracta puede tener variables finales, no finales, estáticas y no estáticas.
  • La clase abstracta puede proporcionar la implementación de la interfaz.

Interfaz

  • La interfaz puede tener métodos predeterminados, estáticos y abstractos.
  • La interfaz soporta herencia múltiple.
  • La interfaz solo tiene variables estáticas y finales.
  • La interfaz no puede proporcionar la implementación de la clase abstracta.

Trataré de responder usando un escenario práctico para mostrar la distinción entre los dos.

Las interfaces vienen con una carga útil cero, es decir, no se debe mantener ningún estado y, por lo tanto, son una mejor opción para simplemente asociar un contrato (capacidad) con una clase.

Por ejemplo, digamos que tengo una clase de Tarea que realiza alguna acción, ahora para ejecutar una tarea en un hilo separado, realmente no necesito extender la clase de Hilo. La mejor opción es hacer que la Tarea implemente la Interfaz ejecutable de ejecución (es decir, implemente su método run () ) y luego pasar el objeto de esta clase de tarea a una instancia de Thread y llamar a su método start ().

Ahora puedes preguntar qué pasaría si Runnable fuera una clase abstracta.

Bueno, técnicamente eso fue posible, pero en cuanto al diseño, habría sido una mala elección, ya que:

  • Runnable no tiene un estado asociado y tampoco "ofrece" ninguna implementación predeterminada para el método run ()
  • La tarea tendría que ampliarla por lo que no podría extender ninguna otra clase.
  • La tarea no tiene nada que ofrecer como especialización a la clase Runnable, todo lo que necesita es anular el método run ()

En otras palabras, la clase de tarea necesitaba una capacidad para ejecutarse en un subproceso que logró al implementar los versos de la interfaz de Runnable extendiendo la clase de subproceso que lo convertiría en un subproceso.

Simplemente colóquenos la interfaz para definir una capacidad (contrato), mientras que use una clase abstracta para definir la implementación esquelética (común / parcial) de la misma.

Descargo de responsabilidad: ejemplo tonto sigue, trate de no juzgar :-P

interface Forgiver { void forgive(); } abstract class GodLike implements Forgiver { abstract void forget(); final void forgive() { forget(); } }

Ahora se le ha dado la opción de ser GodLike pero puede elegir ser Forgiver solamente (es decir, no GodLike) y hacer:

class HumanLike implements Forgiver { void forgive() { // forgive but remember } }

O puede elegir ser GodLike y hacer:

class AngelLike extends GodLike { void forget() { // forget to forgive } }

PS con interfaz java 8 también puede tener métodos tanto estáticos como predeterminados (implementación reemplazable) y, por lo tanto, la diferencia entre la interfaz b / w y la clase abstracta se reducen aún más.


hmm, ahora la gente tiene un enfoque práctico, está en lo cierto, pero la mayoría de los entrevistadores se parecen a sus requisitos actuales y desean un enfoque práctico.

Después de terminar tu respuesta debes saltar sobre el ejemplo:

Resumen:

Por ejemplo, tenemos una función de salario que tiene algunos parámetros comunes para todos los empleados. entonces podemos tener una clase abstracta llamada CTC con un cuerpo de método parcialmente definido que se extenderá por todo tipo de empleado y se redefinirá según su capacidad adicional. Para funcionalidad común.

public abstract class CTC { public int salary(int hra, int da, int extra) { int total; total = hra+da+extra; //incentive for specific performing employee //total = hra+da+extra+incentive; return total; } } class Manger extends CTC { } class CEO extends CTC { } class Developer extends CTC { }

Interfaz

La interfaz en java permite tener una funcionalidad intercalar sin extender esa y usted debe ser claro con la implementación de la firma de la funcionalidad que desea introducir en su aplicación. Te obligará a tener definición. Para diferentes funcionalidades. interfaz pública EmployeType {

public String typeOfEmployee(); } class ContarctOne implements EmployeType { @Override public String typeOfEmployee() { return "contract"; } } class PermanentOne implements EmployeType { @Override public String typeOfEmployee() { return "permanent"; } }

puede tener tal actividad forzada con clase abstracta también por métodos definidos como abstractos, ahora una clase que extiende la clase abstracta reminando una abstracta hasta que anule esa función abstracta.


su respuesta es correcta, pero el entrevistador necesita que usted se diferencie según la perspectiva de ingeniería de software, no de acuerdo con los detalles de Java.

Palabras simples:

Una Interfaz es como la interfaz de una tienda, todo lo que se muestra en ella debe estar allí en la tienda, por lo que cualquier método en la Interfaz debe implementarse en la clase concreta. Ahora qué pasa si algunas clases comparten algunos métodos exactos y varía en otros. Supongamos que la Interfaz trata de una tienda que contiene dos cosas y supongamos que tenemos dos tiendas que contienen equipo deportivo, pero una tiene ropa extra y la otra tiene zapatos adicionales. Entonces, lo que haces es crear una clase abstracta para el deporte que implemente el método de los deportes y deje el otro método sin implementar. Clase abstracta aquí significa que esta tienda no existe en sí misma, pero es la base para otras clases / tiendas. De esta manera, usted está organizando el código, evitando errores al replicar el código, unificando el código y asegurando la reutilización de alguna otra clase.


Casi todo parece estar cubierto aquí ya. Agregando solo un punto más sobre la implementación práctica de la abstractclase:

abstractla palabra clave también se usa para evitar que se cree una instancia de una clase. Si tienes una clase concreta de la que no quieres ser instanciado, hazlo abstract.


Elige Interfaz en Java para evitar el problema de diamante en herencia múltiple .

Si desea que todos sus métodos sean implementados por su cliente, vaya a la interfaz. Significa que diseñas toda la aplicación en abstracto.

Elige clase abstracta si ya sabes lo que está en común. Por ejemplo, tomar una clase abstracta Car. En el nivel superior se implementan los métodos de coche comunes como calculateRPM(). Es un método común y permite que el cliente implemente su propio comportamiento, como
calculateMaxSpeed()etc. Probablemente lo habría explicado dando algunos ejemplos en tiempo real que haya encontrado en su trabajo diario.


En clase abstracta, puede escribir la implementación predeterminada de los métodos! Pero en la interfaz no se puede. Básicamente, en la interfaz existen métodos virtuales puros que deben ser implementados por la clase que implementa la interfaz.


Hago entrevistas para el trabajo y me gustaría ver su respuesta desfavorablemente (lo siento, pero soy muy honesto). Suena como si hubiera leído sobre la diferencia y revisado una respuesta, pero tal vez nunca la haya usado en la práctica.

Una buena explicación de por qué usaría cada uno puede ser mucho mejor que tener una explicación precisa de la diferencia. Los empleadores al final quieren que los programadores hagan cosas que no las conozcan, lo que puede ser difícil de demostrar en una entrevista. La respuesta que dio sería buena si solicita un trabajo técnico o de documentación, pero no un rol de desarrollador.

Mucha suerte con las entrevistas en el futuro.

También mi respuesta a esta pregunta es más sobre la técnica de entrevista en lugar del material técnico que ha proporcionado. Quizás considere leer sobre esto. https://workplace.stackexchange.com/ puede ser un lugar excelente para este tipo de cosas.


Incluso me he enfrentado a la misma pregunta en múltiples entrevistas y créeme, hace que sea muy difícil convencer al entrevistador. Si soy inherente a todas las respuestas anteriores, debo agregar un punto clave más para hacerlo más convincente y utilizar OO en su mejor momento

En caso de que no esté planeando ninguna modificación en las reglas , para la subclase a seguir, por un largo tiempo, vaya a la interfaz, ya que no podrá modificarla y si lo hace, debe ir por la cambios en todas las demás subclases, mientras que, si lo cree, desea reutilizar la funcionalidad, establecer algunas reglas y también hacerla abierta para su modificación , vaya a la clase Resumen.

Piense de esta manera, ha utilizado un servicio de consumibles o ha proporcionado algún código a world y tiene la oportunidad de modificar algo, suponga un control de seguridad. Y si soy un consumidor del código y una mañana después de una actualización, Encontrar todas las marcas de lectura en mi Eclipse, toda la aplicación está caída. Entonces, para evitar tales pesadillas, use Abstract over Interfaces.

Creo que esto podría convencer al entrevistador hasta cierto punto ... Feliz entrevista por delante.


La principal diferencia que he observado es que la clase abstracta nos proporciona un comportamiento común implementado y las subclases solo necesitan implementar la funcionalidad específica correspondiente a ellas. donde en cuanto a una interfaz solo especificará qué tareas deben realizarse y la interfaz no dará implementaciones. Puedo decir que especifica el contrato entre él y las clases implementadas.


La principal diferencia que he observado es que la clase abstracta nos proporciona un comportamiento común implementado y las subclases solo necesitan implementar la funcionalidad específica correspondiente a ellas. donde en cuanto a una interfaz solo especificará qué tareas deben realizarse y la interfaz no dará implementaciones. Puedo decir que especifica el contrato entre él y las clases implementadas.


Las clases abstractas están destinadas a ser heredadas de, y cuando una clase hereda de otra, significa que existe una fuerte relación entre las 2 clases. Por otro lado, con una interfaz, la relación entre la interfaz en sí misma y la clase que implementa la interfaz no es necesariamente sólida. Entonces, podemos resumir este primer punto diciendo que una clase abstracta sería más apropiada cuando hay una relación sólida entre la clase abstracta y las clases que se derivarán de ella. Nuevamente, esto se debe a que una clase abstracta está estrechamente vinculada a la herencia, lo que implica una relación sólida. Pero, con las interfaces, no es necesario que haya una relación sólida entre la interfaz y las clases que implementan la interfaz. La interfaz de Java puede extender la interfaz múltiple, también la clase Java puede implementar múltiples interfaces,Lo que significa que la interfaz puede proporcionar más soporte para el polimorfismo que la clase abstracta. Al extender la clase abstracta, una clase solo puede participar en una jerarquía de tipos, pero al usar la interfaz puede formar parte de múltiples jerarquías de tipos.

Para implementar la interfaz en Java, hasta que su clase sea abstracta, debe proporcionar la implementación de todos los métodos, lo cual es muy doloroso. Por otro lado, la clase abstracta puede ayudarlo en este caso al proporcionar una implementación predeterminada.


Las clases abstractas no son abstracción pura, ya que su colección de elementos concretos (métodos implementados) y métodos no implementados. Pero las interfaces son pura abstracción porque solo hay métodos no implementados, no métodos concretos.

¿Por qué clases abstractas?

  1. Si el usuario quiere escribir funcionalidad común para todos los objetos.
  2. Las clases abstractas son la mejor opción para la reimplementación en el futuro que agregar más funcionalidad sin afectar al usuario final.

¿Por qué interfaces?

  1. Si el usuario quiere escribir una funcionalidad diferente, esa sería una funcionalidad diferente en los objetos.
  2. Las interfaces son la mejor opción, ya que si no es necesario modificar los requisitos una vez que se ha publicado la interfaz.

Por lo que entiendo, una Interfaz, que consta de variables y métodos finales sin implementaciones, es implementada por una clase para obtener un grupo de métodos o métodos que están relacionados entre sí. Por otro lado, una clase abstracta, que puede contener variables y métodos no finales con implementaciones, se usa generalmente como una guía o una superclase de la que se heredan todas las clases relacionadas o similares. En otras palabras, una clase abstracta contiene todos los métodos / variables que comparten todas sus subclases.


Sí, sus respuestas fueron técnicamente correctas, pero cuando se equivocó no les mostró que comprende las ventajas y desventajas de elegir una sobre la otra. Además, probablemente estaban preocupados / asustados por la compatibilidad de su base de código con las actualizaciones en el futuro. Este tipo de respuesta puede haber ayudado (además de lo que dijo):

"La elección de una clase abstracta sobre una clase de interfaz depende de lo que proyectemos que será el futuro del código.

Las clases abstractas permiten una mejor compatibilidad hacia adelante porque puede continuar agregando comportamiento a una clase abstracta en el futuro sin romper su código existente -> esto no es posible con una clase de interfaz.

Por otro lado, las clases de interfaz son más flexibles que las clases abstractas. Esto se debe a que pueden implementar múltiples interfaces . La cuestión es que Java no tiene múltiples herencias, por lo que usar clases abstractas no te permitirá usar ninguna otra estructura de jerarquía de clases ...

Entonces, al final, una buena regla general de oro es: Prefiero usar Clases de interfaz cuando no haya implementaciones predeterminadas / existentes en su base de código. Y, use Abstract Classes para preservar la compatibilidad si sabe que actualizará su clase en el futuro ".

¡Buena suerte en tu próxima entrevista!


Una interfaz es como un conjunto de genes que están documentados públicamente que tienen algún tipo de efecto: una prueba de ADN me dirá si los tengo, y si los tengo, puedo hacer público que es un "portador "y parte de mi comportamiento o estado se ajustará a ellos. (Pero, por supuesto, es posible que tenga muchos otros genes que proporcionan rasgos fuera de este ámbito).

Una clase abstracta es como el antepasado muerto de una especie de un solo sexo (*): no se le puede dar vida, pero una descendiente viva (es decir, no abstracta ) hereda todos sus genes.

(*) Para estirar esta metáfora, digamos que todos los miembros de la especie viven hasta la misma edad. Esto significa que todos los antepasados ​​de un antepasado muerto también deben estar muertos, e igualmente, todos los descendientes de un antepasado vivo deben estar vivos.



Una interfaz es un "contrato" donde la clase que implementa el contrato promete implementar los métodos. Un ejemplo en el que tuve que escribir una interfaz en lugar de una clase fue cuando estaba actualizando un juego de 2D a 3D. Tuve que crear una interfaz para compartir clases entre la versión 2D y la versión 3D del juego.

package adventure; import java.awt.*; public interface Playable { public void playSound(String s); public Image loadPicture(String s); }

Luego, puedo implementar los métodos basados ​​en el entorno, y aún puedo llamarlos desde un objeto que no sabe qué versión del juego se está cargando.

public class Adventure extends JFrame implements Playable

public class Dungeon3D extends SimpleApplication implements Playable

public class Main extends SimpleApplication implements AnimEventListener, ActionListener, Playable

Normalmente, en el mundo del juego, el mundo puede ser una clase abstracta que realiza métodos en el juego:

public abstract class World... public Playable owner; public Playable getOwner() { return owner; } public void setOwner(Playable owner) { this.owner = owner; }