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

469

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 implementen 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 de forma predeterminada. Una clase abstracta de Java puede tener los sabores habituales de los miembros de la clase como privados, protegidos, etc.

Se debe implementar una interfaz Java utilizando la palabra clave "implementos"; Una clase abstracta de Java debe ampliarse con la palabra clave "extiende".

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

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

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

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?

Pensador
fuente
32
¿Quizás su respuesta parecía que estaba diciendo algo que no entiende? Puede ser que simplemente necesite cambiar el estilo de decirle al que más se parezca a sus propias palabras.
Kirill Kobelev el
19
Respondiste con una lista de diferencias técnicas (bastante correctas). El entrevistador probablemente buscaba una respuesta más conceptual (por ejemplo, sobre qué base elegiría entre usar una interfaz y una clase abstracta).
Ted Hopp
15
Olvidó decir que las clases abstractas tienen constructores, aunque no puede crear una instancia de una clase abstracta, la constante. es utilizado por las clases secundarias. Las interfaces indican "qué" pero no "cómo" porque definen un contrato (lista de métodos) mientras que un abst. La clase también puede indicar "cómo" (implementar una metanfetamina). Usando int. puede emular herencia múltiple (una clase puede implementar múltiples int. pero solo extender una clase). Usando int. puede tener un tipo base para dif. familias: Flyer f = new Plane (); Flyer f2 = new Bird (); Bird y Plane no corresponden a la misma familia, pero ambos pueden volar (son volantes).
Francisco Goldenstein
77
A partir de java8, las interfaces pueden contener métodos ... más allá del concepto OO, estas llamadas "diferencias" pueden cambiar cualquier día.
portador del anillo
15
No tengo ningún problema con su respuesta, y no creo que el entrevistador tenga ningún problema para burlarse del "conocimiento del libro". Los entrevistadores no siempre saben las respuestas correctas a las preguntas que hacen, y algunas entrevistas solo sirven para advertirle que no trabaje allí.
Marqués de Lorne

Respuestas:

513

Primero te daré un ejemplo:

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

Supongamos que tiene 3 bases de datos en su aplicación. Luego, todas y cada una de las implementaciones de esa base de datos deben definir los 2 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é encryptPassword()pasa si no depende de la base de datos y es lo mismo para cada clase? Entonces lo anterior no sería un buen enfoque.

En cambio, 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.

Vimal Bera
fuente
97
No estoy seguro de que esto realmente explique la diferencia ... seguro que es una buena técnica. Supongo que también vale la pena señalar que Java 8 finalmente admitió que C ++ tenía razón y que se puede hacer una herencia múltiple y puede tener un uso, por lo que las interfaces ahora pueden definir no solo las firmas de funciones sino también proporcionar implementaciones predeterminadas. Como tal, sería preferible usar una interfaz.
thecoshman
1
@thecoshman ¿Qué diferencia habría si abordara el problema como en la respuesta (clase abstracta con un método implementado y el otro resumen) o definiera una interfaz con una implementación de método predeterminada? Básicamente, lo que estoy tratando de decir es que usted escribió que 'sería preferible usar una interfaz' y mi pregunta es: ¿por qué?
Neutrino
1
Entonces, creo que es justo decir que con las interfaces, la implementación de lo que se ha definido depende de la clase que realmente implementa la interfaz, mientras que las cosas en una clase abstracta son "centrales" para las clases que extienden la clase; es decir, no cambia.
orrymr
44
@Neutrino A pesar de que Java le permite implementar múltiples interfaces, cada una de las cuales ofrece implementaciones predeterminadas para funciones, solo puede extender una sola clase. Como tal, el uso de una interfaz puede proporcionar más flexibilidad para aquellos que quieran usarla, junto con otras interfaces.
thecoshman
3
@HiradNikoo Perdón por el comentario tardío, pero me topé con este hilo. También puede considerar la herencia de clases como una relación IS-A, mientras que las interfaces significan "tiene una cierta funcionalidad".
Alexander Jank
206

Nada es perfecto en este mundo. Es posible que hayan estado esperando un enfoque más práctico.

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

  1. Las interfaces son reglas (reglas porque debes darles una implementación que no puedes 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 lo que se debe hacer, pero no de cómo se hará. Entonces, la implementación depende completamente del desarrollador siguiendo las reglas dadas (significa la firma de los métodos).

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

  4. Las declaraciones abstractas son como reglas a seguir y las implementaciones concretas son como pautas (puede usarlo tal como está o puede ignorarlo anulando y dándole su propia implementación).

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

Editar: 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 implementación para los métodos predeterminados de interfaz.

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 del 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 ambos

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 ambas interfaces anteriores, debe proporcionar la implementación del método defaultMethod (), de lo contrario, el compilador arrojará un error de tiempo de compilación.

Shailesh Saxena
fuente
11
+1, esta es realmente una buena respuesta para evitar la confusión. Pero no vi ningún enlace y no tengo idea de por qué citó esas valiosas líneas. Hazlos como puntos si es posible :).
Suresh Atta
Lea mi comentario anterior sobre la emulación de herencia múltiple usando interfaces y usando interfaces para tener un tipo base para clases de diferentes familias. Creo que el entrevistador quiere escuchar ese tipo de respuestas de los entrevistados.
Francisco Goldenstein
Su comentario también apunta a un buen ejemplo de uso de la interfaz. Escribí lo que siento mientras trabajo día a día. Estas palabras pueden no ser profesionales o precisas. Pero es lo que llegué a saber después de trabajar estrechamente con clases abstractas e interfaces en mi codificación diaria.
Shailesh Saxena
4. Las implementaciones concretas también son las reglas, que tienen la implementación predeterminada.
Luten
@Luten: Según mi conocimiento, si puede evitar / ignorar una regla sin ningún problema, debe ser una guía, no una regla. Por favor, corríjame si estoy equivocado.
Shailesh Saxena
168

Hiciste un buen resumen de las diferencias prácticas en el uso y la implementación, pero no dijiste nada sobre la diferencia de 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. Básicamente es 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 ser creado repetidamente. Las subclases deben completar el comportamiento y tener la opción de anular el comportamiento predefinido (siempre que no esté definido como finalo private).

Encontrará buenos ejemplos en el java.utilpaquete que incluye interfaces como Listy clases abstractas como las AbstractListque ya implementan la interfaz. La documentación oficial describe lo AbstractListsiguiente:

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

Daniel Lerps
fuente
16
Esta debería ser la respuesta. No es una lista de detalles, sino el concepto subyacente que marca la diferencia entre una interfaz y una clase abstracta, no solo en Java sino en general.
edc65
1
Esto es realmente bueno. Por supuesto, otras respuestas también son buenas. Pero esto le dice una advertencia importante sobre la abstractpalabra clave, es decir, cuando un compilador ve esto, saben, la siguiente información está incompleta y necesita implementación . Las interfaces siempre están incompletas, pero las clases abstractas son abstractas porque tenían que tener incomplete (abstract)métodos.
Rakib
85

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

Este concepto se puede entender mejor con un ejemplo:

Considere una clase de pago. El pago puede hacerse de muchas maneras, como PayPal, tarjeta de crédito, etc. Por lo tanto, normalmente tomamos el pago como nuestra interfaz que contiene un makePayment()método 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 puede ser realizado por 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 producen errores de tiempo de compilación.

Existen otras diferencias, pero estas son importantes y pueden haber sido lo que su entrevistador esperaba. Espero que esto haya sido útil.

Satya
fuente
1
Bueno, esta respuesta tiene mucho sentido, y está bastante claro con el ejemplo, cuando aterrizamos eligiendo entre interfacey abstract class.
MAC
"qué hacer pero no sé cómo hacerlo", ya que definimos un método sin realizar implementaciones en él "void makePayment ();", mientras definimos las implementaciones del método en la clase que implementará la interfaz.
Abdel-Raouf
45

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 con el método predeterminado
  3. Método predeterminado y problemas de ambigüedad de herencia múltiple
  4. Puntos importantes sobre los métodos predeterminados de la interfaz de Java:

Método estático de interfaz Java

  1. Método estático de interfaz Java, ejemplo de código, método estático frente a método predeterminado
  2. 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(); 

Método predeterminado

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,

  1. No anular el método predeterminado y heredará el método predeterminado.
  2. Anule el método predeterminado similar a otros métodos que anulamos en la subclase.
  3. 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:

  1. 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.
  2. Los métodos predeterminados de la interfaz Java reducen las diferencias entre las interfaces y las clases abstractas.
  3. 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í.
  4. 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.
  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 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, 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.
  7. 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:

  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 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:

  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, verificación nula, 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 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.
  5. 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 @FunctionalInterfaceha introducido una nueva anotación para marcar una interfaz como Interfaz funcional. @FunctionalInterfaceLa 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:

  1. Cambios en la interfaz de Java 8: método estático, método predeterminado
Andante del cielo
fuente
8
Estoy buscando exactamente este tipo de respuestas actualizadas. Gracias por la respuesta rápida.
Ravindra babu
41

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 página de 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 método existen solo para métodos predeterminados y 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 nuevas funciones a las interfaces de sus bibliotecas y garantizar 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. Redeclare el método predeterminado, que lo hace abstract.
  3. Redefina 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 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 le facilita la organización de métodos auxiliares en sus bibliotecas;

Código de ejemplo de la página de documentación sobre interfacetener staticy defaultmétodos.

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));
    }
}

Use las siguientes pautas para elegir si desea usar una interfaz o una clase abstracta.

Interfaz:

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

Clase abstracta:

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

  2. Comparta el estado común entre clases relacionadas (el estado puede modificarse en clases concretas)

Artículos Relacionados:

Interfaz vs clase abstracta (OO general)

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

Al seguir estos ejemplos, puede comprender que

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

Ravindra babu
fuente
¿Qué quieres decir con "contrato sin estado"? Es el ítem 1 sobre interfaces
Maksim Dmitriev
1
Ausencia de estado mutable. Dado que la interfaz puede tener constantes, los datos pueden mutarse a diferencia de las clases abstractas
Ravindra babu
1
Corrección en la declaración anterior. En la interfaz, los datos no pueden mutarse a diferencia de la clase abstracta
Ravindra babu
2
Esta es la mejor respuesta. No solo aborda Java8, sino que también explica en qué situaciones particulares usaría cualquiera de ellos.
Shuklaswag
El concepto de statelessinterfaz es un buen éxito. La interfaz no puede tener ningún estado (la interfaz podría tener constantes pero son finales / estáticas, por lo tanto inmutables).
Kaihua
22

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

Lo que más me preocupa es, ¿qué tan sólido fue su ejemplo? ¿Se molestó 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 y a todos los demás lectores en sus futuras entrevistas

VictorCreator
fuente
1
el enlace se comparte es realmente impresionante
Premraj
Puede proporcionar una implementación predeterminada en las interfaces de Java utilizando la palabra clave predeterminada
Ogen
21

Muchos desarrolladores junior cometen el error de pensar que las interfaces, las clases abstractas y concretas son pequeñas variaciones de la misma cosa, y eligen una de ellas únicamente por razones técnicas: ¿Necesito herencia múltiple? ¿Necesito algún lugar para poner métodos comunes? ¿Debo molestarme con algo más que una clase concreta? Esto está mal, y oculto en estas preguntas está el principal problema: "Yo" . Cuando escribes código para ti, por ti mismo, rara vez piensas en otros desarrolladores presentes o futuros trabajando en o con tu código.

Las interfaces y las clases abstractas, aunque aparentemente son 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 son lo que busco cuando estoy entrevistando, y es un resumen lo suficientemente compacto. Sigue leyendo para más detalles.

Resumen alternativo

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

Por ejemplo

Para decirlo de otra manera: una clase concreta hace el trabajo real, de una manera muy específica. Por ejemplo, un ArrayListusa 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, unLinkedListusa nodos de doble enlace para almacenar una lista de objetos, que en su lugar ofrece 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 usará. Cuando intentas exprimir el rendimiento de una lista con la que estás interactuando mucho, y cuando eliges el tipo de lista, debes elegir con cuidado cuál estás creando una instancia.

Por otro lado, a los usuarios de alto nivel de una lista realmente no les importa cómo se implementa realmente, y deberían estar aislados de estos detalles. Imaginemos que Java no expuso la Listinterfaz, sino que solo tenía una Listclase concreta que en realidad LinkedListes lo que es ahora. Todos los desarrolladores de Java habrían adaptado su código para que se ajuste a los detalles de implementación: evite el acceso aleatorio, agregue un caché para acelerar el acceso o simplemente vuelva ArrayLista implementarlo por sí mismo, aunque sería incompatible con todos los demás códigos que realmente funcionan Listsolo. Eso sería terrible ... Pero ahora imagine que los maestros de Java realmente se dan cuenta de que una lista vinculada es terrible para la mayoría de los casos de uso reales, y decidieron cambiar a una lista de matriz para su únicoListclase disponible Esto afectaría el rendimiento de cada programa Java en el mundo, y la gente no estaría contenta con eso. Y el principal culpable es que los detalles de 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 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 tentarían a los programadores a ajustar 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 las interfaces y las clases concretas. Se supone que ayuda a las implementaciones a compartir código común o aburrido. Por ejemplo, AbstractCollectionproporciona implementaciones básicas isEmptybasadas en el tamaño es 0, containscomo iterar y comparar, addAllcomo repetido add, y así sucesivamente. Esto permite que las implementaciones se centren en las partes cruciales que las diferencian: cómo almacenar y recuperar datos.

Otra perspectiva: API versus SPI

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 auxiliares de alta cohesión que se utilizarán al implementar una interfaz, asumiendo cierto 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 foco está en quién lo usa , y para un SPI el foco 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. Agregar 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 utilizan 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 exceptionresguardos vacíos , lo que al menos permitirá que una versión anterior de una implementación de servicio aún se compile y ejecute.

Una nota sobre Java 8 y los métodos predeterminados

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 borrosa, esto no fue para que las implementaciones puedan reutilizar el código, sino para que sea más fácil cambiar las interfaces que sirven como API y como SPI (o se usan 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 es generalmente el enfoque utilizado en la escuela y en la mayoría de los libros de tecnología sobre un idioma: qué es una cosa, no cómo usarlo en la práctica, especialmente en aplicaciones a gran escala. .

Aquí hay una analogía: supuse que la pregunta era:

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

La respuesta técnica suena así:

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, por ejemplo, digamos que puede ir al punto de vista para obtener una vista agradable, 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 se pueden usar al mismo tiempo para diferentes propósitos, y el aspecto "hacerlo" no es lo más importante de ninguna de las dos opciones. . La respuesta carece de perspectiva, muestra una forma inmadura de pensar, mientras presenta correctamente "hechos" verdaderos.

Sergiu Dumitriu
fuente
¿Quiso decir "bajo acoplamiento"?
user2418306
@ user2418306 No, la cohesión es un término más genérico que incluye el acoplamiento, aunque son sinónimos cercanos, y cualquiera de los términos hubiera funcionado.
Sergiu Dumitriu el
9

¿Qué hay de pensar de la siguiente manera:

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

Entonces, cuando tienes una clase abstracta Mamíferos, una subclase Humana y una interfaz de Conducción, entonces puedes decir

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

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

akohout
fuente
9

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 3D del juego.

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

Entonces puedo implementar los métodos basados ​​en el entorno, sin dejar de 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

Típicamente, 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;
    }
Niklas R.
fuente
6

Las clases abstractas no son pura abstracción porque su colección de métodos concretos (métodos implementados) así como 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 desea escribir una funcionalidad común para todos los objetos.
  2. Las clases abstractas son la mejor opción para la reimplementación en el futuro que para agregar más funcionalidad sin afectar al usuario final.

¿Por qué las interfaces?

  1. Si el usuario desea escribir una funcionalidad diferente, sería una funcionalidad diferente en los objetos.
  2. Las interfaces son la mejor opción si no es necesario modificar los requisitos una vez que la interfaz ha sido publicada.
Sarfaraz Ahamad
fuente
5

Una interfaz es como un conjunto de genes que están documentados públicamente para tener algún tipo de efecto: una prueba de ADN me dirá si los tengo, y si lo hago, puedo dar a conocer públicamente que soy un "portador" "y parte de mi comportamiento o estado se ajustará a ellos. (Pero, por supuesto, puedo tener muchos otros genes que proporcionan rasgos fuera de este alcance).

Una clase abstracta es como el ancestro muerto de una especie de un solo sexo (*): no puede ser traída a la vida, pero un descendiente vivo (es decir, no abstracto ) 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, y del mismo modo, todos los descendientes de un antepasado vivo deben estar vivos.

Steve Chambers
fuente
4

Hago entrevistas por trabajo y también miraría desfavorablemente su respuesta (lo siento, pero soy muy honesto). Parece que has leído sobre la diferencia y revisado una respuesta, pero quizás nunca la hayas 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. En última instancia, los empleadores quieren que los programadores hagan cosas que no saben, 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 entrevistas en el futuro.

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

Adrian
fuente
1
¿Podrías decirme cómo lo respondiste? Puede ser que me pueda ayudar.
code_fish
darle la respuesta ofrece mucho menos que ayudarlo a resolverlo, básicamente dé un ejemplo práctico de cuándo usaría cada uno y explique por qué cada uno es adecuado para las diferentes tareas.
Adrian
4

Eliges Interfaz en Java para evitar el Problema Diamante en herencia múltiple .

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

Eliges la clase abstracta si ya sabes lo que hay en común. Por ejemplo, tome una clase abstracta Car. En un nivel superior, implementa los métodos comunes de automóviles 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.

MaheshVarma
fuente
3

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


fuente
3

Incluso me he enfrentado a la misma pregunta en múltiples entrevistas y créanme que hace su tiempo miserable convencer al entrevistador. Si inherente a todas las respuestas de arriba, entonces necesito 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 que se siga la subclase, en el futuro, vaya a la interfaz, ya que no podrá modificarla y, si lo hace, debe ir a la cambios en todas las otras subclases, mientras que, si piensa, desea reutilizar la funcionalidad, establecer algunas reglas y también hacer que se abran para modificaciones , vaya a la clase Resumen.

Piense de esta manera, ha utilizado un servicio de consumibles o ha proporcionado algún código al mundo 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á inactiva. Entonces, para evitar tales pesadillas, use Resumen sobre interfaces

Creo que esto podría convencer al entrevistador hasta cierto punto ... Felices entrevistas por delante.

vinod bazari
fuente
2

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

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

Por ejemplo, nunca crearía una clase abstracta con 1 subclase concreta porque las clases abstractas se tratan de compartir el comportamiento. Pero bien podría 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 alguna nueva clase abstracta que ni siquiera existía cuando creé la interfaz.

Eso podría haber parecido un poco demasiado libro (aunque nunca lo he visto así en ningún lugar que yo recuerde). Si el entrevistador (o el OP) realmente quisiera más de mi experiencia personal al respecto, habría estado listo con anécdotas de que una interfaz ha evolucionado por necesidad y viceversa.

Una cosa más. Java 8 ahora le permite poner código predeterminado en una interfaz, difuminando aún más la línea entre las interfaces y las clases abstractas. Pero por lo que he visto, esa característica es utilizada en exceso incluso por los creadores de las bibliotecas centrales de Java. Esa característica se agregó, y con razón, para permitir extender una interfaz sin crear incompatibilidad binaria. Pero si está creando un nuevo tipo definiendo una interfaz, entonces la interfaz debe ser SOLO una interfaz. Si también desea proporcionar un código común, haga una clase auxiliar (abstracta o concreta). No esté abarrotando su interfaz desde el principio con la funcionalidad que desee cambiar.

Teto
fuente
2

La diferencia básica entre la interfaz y la clase abstracta es que la interfaz admite herencia múltiple, pero no la clase abstracta.

En la clase abstracta también puede proporcionar todos los métodos abstractos como la interfaz.

¿Por qué se requiere clase abstracta?

En algunos escenarios, mientras procesa la solicitud del usuario, la clase abstracta no sabe qué intención del usuario. En ese escenario, definiremos un método abstracto en la clase y le preguntaremos al usuario quién extiende esta clase, por favor proporcione su intención en el método abstracto. En este caso las clases abstractas son muy útiles.

¿Por qué se requiere interfaz?

Digamos que tengo un trabajo que no tengo experiencia en esa área. Ejemplo, si quieres construir un edificio o presa, ¿qué harás en ese escenario?

  1. identificará cuáles son sus requisitos y hará un contrato con esos requisitos.
  2. Luego llame a las licitaciones para construir su proyecto
  3. Quien construya el proyecto, eso debería satisfacer sus requisitos. Pero la lógica de construcción es diferente de un proveedor a otro.

Aquí no me preocupo por la lógica de cómo construyeron. El objeto final satisfizo mis requisitos o no, ese es solo mi punto clave.

Aquí sus requisitos llamados interfaz y constructores se llaman implementador.

Dharisi Suresh
fuente
2

En pocas palabras, respondería de esta manera:

  • La herencia a través de la jerarquía de clases implica una herencia de estado ;
  • Considerando que la herencia a través de interfaces significa herencia de comportamiento ;

Las clases abstractas pueden tratarse como algo entre estos dos casos (presenta algún estado pero también obliga a definir un comportamiento), una clase completamente abstracta es una interfaz (este es un desarrollo adicional de clases que consisten en métodos virtuales solo en C ++ como hasta donde sé de su sintaxis).

Por supuesto, a partir de Java 8, las cosas cambiaron ligeramente, pero la idea sigue siendo la misma.

Supongo que esto es suficiente para una entrevista típica de Java, si no te están entrevistando a un equipo compilador.

Gleb Stromov
fuente
1

Por lo que entiendo, una interfaz, que se compone de variables finales y métodos 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, generalmente se usa como una guía o como una superclase de la cual todas las clases relacionadas o similares heredan. En otras palabras, una clase abstracta contiene todos los métodos / variables que comparten todas sus subclases.

Marz
fuente
1

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

dg_no_9
fuente
1

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):

"Elegir una clase abstracta sobre una clase de interfaz depende de lo que proyectemos 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 es: prefiera usar las clases de interfaz cuando no haya implementaciones existentes / predeterminadas en su base de código. Y use las clases abstractas para preservar la compatibilidad si sabe que actualizará su clase en el futuro ".

¡Buena suerte en tu próxima entrevista!

Jaxian
fuente
1

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

Las interfaces vienen con 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, supongamos que tengo una clase de Tarea que realiza alguna acción, ahora para ejecutar una tarea en un subproceso separado, realmente no necesito extender la clase de subproceso. Una mejor opción es hacer que la Tarea implemente la interfaz Ejecutable (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 puede preguntar qué pasa si Runnable era una clase abstracta.

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

  • Runnable no tiene ningún estado asociado y tampoco 'ofrece' ninguna implementación predeterminada para el método run ()
  • La tarea tendría que extenderla, 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 Task necesitaba una capacidad para ejecutarse en un subproceso que logró mediante la implementación de versos de interfaz Runnable que extendían la clase Thread que lo convertiría en un subproceso.

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

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

interface Forgiver {
    void forgive();
}

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

Ahora se te ha dado la opción de ser GodLike, pero puedes elegir ser solo Perdonador (es decir, no GodLike) y hacer:

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

O puede elegir ser Dios y hacer:

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

La PS con interfaz java 8 también puede tener métodos estáticos y predeterminados (implementación reemplazable) y, por lo tanto, la diferencia de interfaz en blanco y negro y la clase abstracta se reducen aún más.

sactiw
fuente
1

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 instancia una clase. Si tiene una clase concreta de la que no desea que se cree una instancia, hágalo abstract.

Espada
fuente
1

hmm, ahora la gente tiene un enfoque práctico hambriento, tienes toda la razón, pero la mayoría de los entrevistadores se ve según su requisito actual y quiere un enfoque práctico.

después de terminar tu respuesta, debes saltar al ejemplo:

Resumen:

Por ejemplo, tenemos una función salarial que tiene algunos parámetros comunes a todos los empleados. entonces podemos tener una clase abstracta llamada CTC con cuerpo de método parcialmente definido y se extenderá por todo tipo de empleado y se redefinirá según sus beneficios adicionales. Para la 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 funcionalidad interfcae sin extender esa y debe ser claro con la implementación de la firma de funcionalidad que desea introducir en su aplicación. te obligará a tener una definición. Para diferentes funcionalidades.

public interface 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 una actividad tan forzada con la clase abstracta también mediante métodos definidos como abstractos, ahora una clase que extiende la clase abstracta recuerda una abstracta hasta que anule esa función abstracta.

RTA
fuente
1

Por lo que entiendo y 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 defino un resumen de clase cuando sé la implementación requerida para algunos métodos de la clase y algunos métodos aún no sé cuál será la implementación (podríamos conocer la firma de la función pero no la implementación). Hago esto para que más adelante en la parte de desarrollo, cuando sé cómo se implementarán estos métodos, pueda extender esta clase abstracta e implementar estos métodos.

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

Akash Lodha
fuente
0

Creo que lo que el entrevistador intentaba llegar era probablemente la diferencia entre la interfaz y la implementación.

La interfaz, no una interfaz Java, sino "interfaz" en términos más generales, a un módulo de código es, básicamente, el contrato realizado con el código del 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 particular de más de una manera diferente, e incluso cambiar la implementación sin que el código del cliente se dé cuenta del cambio.

Una interfaz Java solo debe usarse como una interfaz en el sentido genérico anterior, para definir cómo se comporta la clase en beneficio del código del cliente que usa 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 sean invocados por el código del cliente, y en principio debería tener un montón de Javadoc para cada método que describa qué hace ese método. La razón más convincente para usar una interfaz es si planea tener múltiples implementaciones diferentes de la interfaz, quizás seleccionando una implementación dependiendo de la configuración de implementación.

Una clase abstracta de Java, por el contrario, proporciona una implementación parcial de la clase, en lugar de tener el propósito principal de especificar una interfaz. Debe usarse cuando varias clases comparten código, pero cuando también 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, a la vez que deja en claro que partes de la implementación no están presentes en la clase abstracta y se espera que sean proporcionadas por subclases.

Warren Dew
fuente
0

su respuesta es correcta, pero el entrevistador necesita que lo diferencie de acuerdo con la perspectiva de la 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 él 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ían en otros? Supongamos que la interfaz se 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 extra. Entonces, lo que debe hacer es crear una clase abstracta para Sport que implemente el método Sports y deje el otro método sin implementar. La clase abstracta aquí significa que esta tienda no existe en sí misma, pero es la base para otras clases / tiendas. De esta forma, está organizando el código, evitando errores de replicación del código, unificando el código y garantizando la reutilización por parte de alguna otra clase.

Mosab Shaheen
fuente