Comment aurais-je dû expliquer la différence entre une interface et une classe abstraite?

469

Dans une de mes interviews, on m'a demandé d'expliquer la différence entre une classe Interface et une classe Abstract .

Voici ma réponse:

Les méthodes d'une interface Java sont implicitement abstraites et ne peuvent pas avoir d'implémentations. Une classe abstraite Java peut avoir des méthodes d'instance qui implémentent un comportement par défaut.

Les variables déclarées dans une interface Java sont par défaut finales. Une classe abstraite peut contenir des variables non finales.

Les membres d'une interface Java sont publics par défaut. Une classe abstraite Java peut avoir les saveurs habituelles des membres de la classe comme privée, protégée, etc.

Une interface Java doit être implémentée à l'aide du mot clé «implements»; Une classe abstraite Java doit être étendue à l'aide du mot-clé «extend».

Une interface peut étendre une autre interface Java uniquement, une classe abstraite peut étendre une autre classe Java et implémenter plusieurs interfaces Java.

Une classe Java peut implémenter plusieurs interfaces mais elle ne peut étendre qu'une seule classe abstraite.

Cependant, l'intervieweur n'était pas satisfait et m'a dit que cette description représentait une " connaissance livresque ".

Il m'a demandé une réponse plus pratique, expliquant quand je choisirais une classe abstraite plutôt qu'une interface, en utilisant des exemples pratiques .

Où me suis-je trompé?

Penseur
la source
32
Peut-être que votre réponse donne l'impression que vous dites quelque chose que vous ne comprenez pas? Il se peut que vous ayez simplement besoin de changer le style de dire à celui qui ressemble davantage à vos propres mots.
Kirill Kobelev
19
Vous avez répondu avec une liste de différences techniques (tout à fait correctes). L'enquêteur était très probablement à la recherche d'une réponse plus conceptuelle (par exemple, sur quelle base choisirait-il d'utiliser une interface et une classe abstraite).
Ted Hopp
15
Vous avez oublié de dire que les classes abstraites ont des constructeurs, même si vous ne pouvez pas instancier une classe abstraite, la const. est utilisé par les classes enfants. Les interfaces indiquent "quoi" mais pas "comment" car elles définissent un contrat (liste de méthodes) alors qu'une abst. La classe peut également indiquer "comment" (implémenter une méth.). En utilisant int. vous pouvez émuler l'héritage multiple (une classe peut implémenter plusieurs int. mais étendre une seule classe). En utilisant int. vous pouvez avoir un type de base pour dif. familles: Flyer f = new Plane (); Flyer f2 = new Bird (); Bird et Plane ne correspondent pas à la même famille mais les deux peuvent voler (sont des flyers).
Francisco Goldenstein
7
Depuis java8, les interfaces peuvent contenir des méthodes .. donc au-delà du concept OO, ces soi-disant "différences" peuvent changer n'importe quel jour.
porteur de l'anneau
15
Je n'ai aucun problème avec votre réponse, et je ne pense pas que l'intervieweur ait quelque chose à se moquer de la «connaissance du livre». Les enquêteurs ne connaissent pas toujours les bonnes réponses aux questions qu'ils posent, et certains entretiens ne servent qu'à vous avertir de ne pas y travailler.
Marquis de Lorne

Réponses:

513

Je vais d'abord vous donner un exemple:

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

Supposons que vous ayez 3 bases de données dans votre application. Ensuite, chaque implémentation de cette base de données doit définir les 2 méthodes ci-dessus:

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
}

Mais si encryptPassword() ne dépend pas de la base de données, et c'est la même chose pour chaque classe? Alors ce qui précède ne serait pas une bonne approche.

Envisagez plutôt cette approche:

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

Désormais, dans chaque classe enfant, il nous suffit d'implémenter une seule méthode - la méthode qui dépend de la base de données.

Vimal Bera
la source
97
Je ne suis pas sûr que cela explique vraiment la différence ... bien sûr, c'est une belle technique. Je suppose qu'il convient également de souligner que Java 8 a finalement admis que C ++ avait raison et que l'héritage multiple peut être effectué et peut avoir une utilisation.Les interfaces peuvent désormais définir non seulement les signatures de fonction, mais également fournir des implémentations par défaut. En tant que tel, l'utilisation d'une interface serait préférable.
thecoshman le
1
@thecoshman Quelle différence cela ferait-il si j'abordais le problème comme dans la réponse (classe abstraite avec une méthode implémentée et l'autre abstraite) ou définissais une interface avec une implémentation de méthode par défaut? Fondamentalement, ce que j'essaie de dire, c'est que vous avez écrit que "l'utilisation d'une interface serait préférable" et ma question est - pourquoi?
Neutrino
1
Donc, je suppose qu'il est juste de dire alors qu'avec les interfaces, l'implémentation de ce qui a été défini appartient à la classe qui implémente réellement l'interface, tandis que le contenu d'une classe abstraite est "central" aux classes qui étendent la classe; c'est-à-dire que cela ne change pas.
orrymr du
4
@Neutrino Bien que Java vous permette d'implémenter plusieurs interfaces offrant chacune des implémentations par défaut pour les fonctions, vous ne pouvez toujours étendre qu'une seule classe. En tant que tel, l'utilisation d'une interface peut offrir plus de flexibilité à ceux qui souhaitent l'utiliser, ainsi que d'autres interfaces.
thecoshman
3
@HiradNikoo Désolé pour le commentaire tardif, mais je suis juste tombé sur ce fil. Vous pouvez également considérer l'héritage de classe comme une relation IS-A, alors que les interfaces signifient "a une certaine fonctionnalité".
Alexander Jank
206

Rien n'est parfait dans ce monde. Ils s'attendaient peut-être davantage à une approche pratique.

Mais après votre explication, vous pouvez ajouter ces lignes avec une approche légèrement différente.

  1. Les interfaces sont des règles (règles parce que vous devez leur donner une implémentation que vous ne pouvez pas ignorer ou éviter, afin qu'elles soient imposées comme des règles) qui fonctionne comme un document de compréhension commun entre les différentes équipes de développement logiciel.

  2. Les interfaces donnent l'idée de ce qui doit être fait mais pas de la manière dont cela sera fait. L'implémentation dépend donc complètement du développeur en suivant les règles données (signifie la signature donnée des méthodes).

  3. Les classes abstraites peuvent contenir des déclarations abstraites, des implémentations concrètes ou les deux.

  4. Les déclarations abstraites sont comme des règles à suivre et des implémentations concrètes sont comme des directives (vous pouvez l'utiliser tel quel ou vous pouvez l'ignorer en remplaçant et en lui donnant votre propre implémentation).

  5. De plus, quelles méthodes avec la même signature peuvent changer le comportement dans différents contextes sont fournies sous forme de déclarations d'interface comme règles à implémenter en conséquence dans différents contextes.

Edit: Java 8 facilite la définition de méthodes par défaut et statiques dans l'interface.

public interface SomeInterfaceOne {

    void usualAbstractMethod(String inputString);

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

Désormais, lorsqu'une classe implémentera SomeInterface, il n'est pas obligatoire de fournir l'implémentation des méthodes d'interface par défaut.

Si nous avons une autre interface avec les méthodes suivantes:

public interface SomeInterfaceTwo {

    void usualAbstractMethod(String inputString);

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

}

Java n'autorise pas l'extension de plusieurs classes car cela entraîne le «problème Diamond» où le compilateur n'est pas en mesure de décider quelle méthode de superclasse utiliser. Avec les méthodes par défaut, le problème du diamant se posera également pour les interfaces. Parce que si une classe implémente les deux

SomeInterfaceOne and SomeInterfaceTwo

et n'implémente pas la méthode par défaut commune, le compilateur ne peut pas décider laquelle choisir. Pour éviter ce problème, en java 8, il est obligatoire d'implémenter des méthodes par défaut communes à différentes interfaces. Si une classe implémente les deux interfaces ci-dessus, elle doit fournir l'implémentation de la méthode defaultMethod () sinon le compilateur générera une erreur de temps de compilation.

Shailesh Saxena
la source
11
+1, c'est vraiment une bonne réponse pour éviter la confusion. Mais je n'ai vu aucun lien et aucune idée de la raison pour laquelle vous avez cité ces précieuses lignes. Faites-les comme points si possible :).
Suresh Atta
Lisez mon commentaire ci-dessus sur l'émulation de l'héritage multiple en utilisant des interfaces et en utilisant des interfaces pour avoir un type de base pour des classes de familles différentes. Je pense que l'intervieweur veut entendre ce genre de réponses des interviewés.
Francisco Goldenstein
Votre commentaire indique également un bon exemple d'utilisation de l'interface. J'ai écrit ce que je ressens en travaillant au quotidien. Ces mots peuvent ne pas être professionnels ou exacts. Mais c'est ce que j'ai appris après avoir travaillé en étroite collaboration avec les classes abstraites et les interfaces dans mon codage quotidien.
Shailesh Saxena
4. Les implémentations concrètes sont également les règles, ayant l'implémentation par défaut.
Luten
@Luten: À ma connaissance, si vous pouvez éviter / ignorer une règle sans aucun problème, cela doit être une directive et non une règle. S'il vous plait corrigez moi si je me trompe.
Shailesh Saxena
168

Vous avez fait un bon résumé des différences pratiques d'utilisation et de mise en œuvre, mais vous n'avez rien dit sur la différence de sens.

Une interface est une description du comportement d'une classe d'implémentation. La classe d'implémentation garantit qu'elle disposera de ces méthodes qui pourront être utilisées dessus. Il s'agit essentiellement d'un contrat ou d'une promesse que la classe doit faire.

Une classe abstraite est une base pour différentes sous-classes qui partagent un comportement qui n'a pas besoin d'être créé à plusieurs reprises. Les sous-classes doivent terminer le comportement et avoir la possibilité de remplacer le comportement prédéfini (tant qu'il n'est pas défini comme finalou private).

Vous trouverez de bons exemples dans le java.utilpaquet qui comprend des interfaces comme Listet des classes abstraites comme AbstractListqui implémentent déjà l'interface. La documentation officielle décrit les éléments AbstractListsuivants:

Cette classe fournit une implémentation squelettique de l'interface List pour minimiser l'effort requis pour implémenter cette interface soutenue par un magasin de données "à accès aléatoire" (tel qu'un tableau).

Daniel Lerps
la source
16
Cela devrait être la réponse. Pas une liste de détails, mais le concept sous-jacent qui fait la différence entre une interface et une classe abstraite, non seulement en Java mais en général.
edc65
1
Ceci est vraiment bon. Bien sûr, les autres réponses sont également bonnes. Mais cela vous indique un avertissement majeur sur le abstractmot-clé, c'est-à-dire lorsqu'un compilateur voit cela, il le sait, les informations suivantes sont incomplètes et doivent être implémentées . Les interfaces sont toujours incomplètes, mais les classes abstraites sont abstraites car elles devaient avoir des incomplete (abstract)méthodes.
Rakib
85

Une interface se compose de variables singleton (final statique public) et de méthodes abstraites publiques. Nous préférons normalement utiliser une interface en temps réel lorsque nous savons quoi faire mais ne savons pas comment le faire .

Ce concept peut être mieux compris par l'exemple:

Considérez une classe de paiement. Le paiement peut être effectué de plusieurs manières, comme PayPal, carte de crédit, etc. Nous prenons donc normalement le paiement comme interface qui contient une makePayment()méthode et CreditCard et PayPal sont les deux classes d'implémentation.

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...
    }
}

Dans l'exemple ci-dessus, CreditCard et PayPal sont deux classes / stratégies d'implémentation. Une interface nous permet également le concept d'héritage multiple en Java qui ne peut pas être accompli par une classe abstraite.

Nous choisissons une classe abstraite lorsqu'il existe des fonctionnalités pour lesquelles nous savons quoi faire et d'autres fonctionnalités que nous savons comment exécuter .

Prenons l'exemple suivant:

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 nous ajoutons des méthodes (concrètes / abstraites) à l'avenir à une classe abstraite donnée, alors la classe d'implémentation n'aura pas besoin de changer son code. Cependant, si nous ajoutons des méthodes dans une interface à l'avenir, nous devons ajouter des implémentations à toutes les classes qui ont implémenté cette interface, sinon des erreurs de compilation se produisent.

Il y a d'autres différences, mais ce sont les principales qui pourraient être ce à quoi votre intervieweur s'attendait. J'espère que cela a été utile.

Satya
la source
1
Eh bien, cette réponse a beaucoup de sens, et c'est assez clair avec l'exemple, quand nous arrivons à choisir entre interfaceet abstract class.
MAC
"que faire mais ne sais pas comment le faire" car nous définissons une méthode sans y faire d'implémentations "void makePayment ();", tout en définissant les implémentations de la méthode dans la classe qui implémentera l'interface.
Abdel-Raouf
45

Différence entre la classe Abstact et l'interface

  1. Classes abstraites et interfaces dans Java 8
  2. Différence conceptuelle:

Méthodes par défaut de l'interface dans Java 8

  1. Qu'est-ce que la méthode par défaut?
  2. Erreur de compilation de la méthode ForEach résolue à l'aide de la méthode par défaut
  3. Méthode par défaut et problèmes d'ambiguïté d'héritage multiples
  4. Points importants sur les méthodes par défaut de l'interface java:

Méthode statique de l'interface Java

  1. Java Interface Static Method, exemple de code, méthode statique vs méthode par défaut
  2. Points importants sur la méthode statique de l'interface java:

Interfaces fonctionnelles Java



Classes abstraites et interfaces dans Java 8

Les changements d'interface Java 8 incluent des méthodes statiques et des méthodes par défaut dans les interfaces. Avant Java 8, nous ne pouvions avoir que des déclarations de méthode dans les interfaces. Mais à partir de Java 8, nous pouvons avoir des méthodes par défaut et des méthodes statiques dans les interfaces.

Après avoir introduit la méthode par défaut, il semble que les interfaces et les classes abstraites soient identiques. Cependant, ils sont encore différents concept dans Java 8.

La classe abstraite peut définir le constructeur. Ils sont plus structurés et peuvent avoir un état qui leur est associé. En revanche, la méthode par défaut ne peut être implémentée qu'en termes d'invocation d'autres méthodes d'interface, sans référence à l'état d'une implémentation particulière. Par conséquent, les deux utilisations à des fins différentes et le choix entre deux dépendent vraiment du contexte du scénario.

Différence conceptuelle:

Les classes abstraites sont valables pour les implémentations squelettiques (c'est-à-dire partielles) des interfaces mais ne devraient pas exister sans interface correspondante.

Ainsi, lorsque les classes abstraites sont effectivement réduites pour être des implémentations squelettiques d'interfaces à faible visibilité, les méthodes par défaut peuvent-elles également supprimer cela? Décidément: Non! L'implémentation d'interfaces nécessite presque toujours une partie ou la totalité de ces outils de création de classe qui manquent aux méthodes par défaut. Et si une interface ne fonctionne pas, c'est clairement un cas spécial, qui ne devrait pas vous induire en erreur.

Méthodes par défaut de l'interface dans Java 8

Java 8 présente la « méthode par défaut » ou (méthodes Defender), qui permet au développeur d'ajouter de nouvelles méthodes aux interfaces sans interrompre l'implémentation existante de ces interfaces. Il offre une flexibilité permettant à l'interface de définir l'implémentation qui sera utilisée par défaut dans le cas où une classe concrète ne fournira pas d'implémentation pour cette méthode.

Prenons un petit exemple pour comprendre comment cela fonctionne:

public interface OldInterface {
    public void existingMethod();
 
    default public void newDefaultMethod() {
        System.out.println("New default method"
               + " is added in interface");
    }
}

La classe suivante se compilera avec succès dans Java JDK 8,

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

Si vous créez une instance de OldInterfaceImpl:

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

Méthode par défaut:

Les méthodes par défaut ne sont jamais définitives, ne peuvent pas être synchronisées et ne peuvent pas remplacer les méthodes d'Object. Ils sont toujours publics, ce qui limite considérablement la possibilité d'écrire des méthodes courtes et réutilisables.

Des méthodes par défaut peuvent être fournies à une interface sans affecter les classes d'implémentation car elle inclut une implémentation. Si chaque méthode ajoutée dans une interface définie avec implémentation, aucune classe d'implémentation n'est affectée. Une classe d'implémentation peut remplacer l'implémentation par défaut fournie par l'interface.

Les méthodes par défaut permettent d'ajouter de nouvelles fonctionnalités aux interfaces existantes sans rompre la mise en œuvre plus ancienne de ces interfaces.

Lorsque nous étendons une interface qui contient une méthode par défaut, nous pouvons effectuer ce qui suit,

  1. Ne pas remplacer la méthode par défaut et héritera de la méthode par défaut.
  2. Remplacez la méthode par défaut similaire aux autres méthodes que nous substituons dans la sous-classe.
  3. Redéclarez la méthode par défaut comme abstraite, ce qui force la sous-classe à la remplacer.

Erreur de compilation de la méthode ForEach résolue à l'aide de la méthode par défaut

Pour Java 8, les collections JDK ont été étendues et la méthode forEach est ajoutée à la collection entière (qui fonctionne en conjonction avec lambdas). De manière conventionnelle, le code ressemble à ci-dessous,

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

Étant donné que cela entraîne chaque classe d'implémentation avec des erreurs de compilation par conséquent, une méthode par défaut a été ajoutée avec une implémentation requise afin que l'implémentation existante ne soit pas modifiée.

L'interface itérable avec la méthode par défaut est ci-dessous,

public interface Iterable<T> {
    public default void forEach(Consumer
                   <? super T> consumer) {
        for (T t : this) {
            consumer.accept(t);
        }
    }
}

Le même mécanisme a été utilisé pour ajouter Stream dans l'interface JDK sans rompre les classes d'implémentation.


Méthode par défaut et problèmes d'ambiguïté d'héritage multiples

Étant donné que java Class peut implémenter plusieurs interfaces et que chaque interface peut définir une méthode par défaut avec la même signature de méthode, les méthodes héritées peuvent donc entrer en conflit les unes avec les autres.

Considérez l'exemple ci-dessous,

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  {
}

Le code ci-dessus ne parviendra pas à compiler avec l'erreur suivante,

java: la classe Impl hérite des valeurs par défaut non liées pour defaultMethod () des types InterfaceA et InterfaceB

Afin de corriger cette classe, nous devons fournir une implémentation de méthode par défaut:

public class Impl implements InterfaceA, InterfaceB {
    public void defaultMethod(){
    }
}

De plus, si nous voulons invoquer l'implémentation par défaut fournie par l'une des super interfaces plutôt que notre propre implémentation, nous pouvons le faire comme suit,

public class Impl implements InterfaceA, InterfaceB {
    public void defaultMethod(){
        // existing code here..
        InterfaceA.super.defaultMethod();
    }
}

Nous pouvons choisir n'importe quelle implémentation par défaut ou les deux dans le cadre de notre nouvelle méthode.

Points importants sur les méthodes par défaut de l'interface java:

  1. Les méthodes par défaut des interfaces Java nous aideront à étendre les interfaces sans avoir peur de casser les classes d'implémentation.
  2. Les méthodes par défaut de l'interface Java ont permis de réduire les différences entre les interfaces et les classes abstraites.
  3. Les méthodes par défaut de l'interface Java 8 nous aideront à éviter les classes utilitaires, telles que toutes les méthodes de la classe Collections peuvent être fournies dans les interfaces elles-mêmes.
  4. Les méthodes par défaut de l'interface Java nous aideront à supprimer les classes d'implémentation de base, nous pouvons fournir l'implémentation par défaut et les classes d'implémentation peuvent choisir celle à remplacer.
  5. L'une des principales raisons de l'introduction de méthodes par défaut dans les interfaces est d'améliorer l'API Collections en Java 8 pour prendre en charge les expressions lambda.
  6. Si une classe de la hiérarchie a une méthode avec la même signature, alors les méthodes par défaut deviennent inutiles. Une méthode par défaut ne peut pas remplacer une méthode de java.lang.Object. Le raisonnement est très simple, c'est parce que Object est la classe de base pour toutes les classes java. Donc, même si nous avons des méthodes de classe Object définies comme méthodes par défaut dans les interfaces, cela sera inutile car la méthode de classe Object sera toujours utilisée. C'est pourquoi, pour éviter toute confusion, nous ne pouvons pas avoir de méthodes par défaut qui remplacent les méthodes de classe Object.
  7. Les méthodes par défaut de l'interface Java sont également appelées méthodes Defender ou méthodes d'extension virtuelle.

Lien de ressource:

  1. Interface avec les méthodes par défaut vs classe abstraite en Java 8
  2. Classe abstraite versus interface à l'ère JDK 8
  3. Evolution de l'interface via des méthodes d'extension virtuelle

Méthode statique de l'interface Java

Java Interface Static Method, exemple de code, méthode statique vs méthode par défaut

La méthode statique de l'interface Java est similaire à la méthode par défaut, sauf que nous ne pouvons pas les remplacer dans les classes d'implémentation. Cette fonctionnalité nous aide à éviter les résultats indésirables en cas de mauvaise implémentation dans les classes d'implémentation. Examinons cela avec un exemple 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;
    }
}

Voyons maintenant une classe d'implémentation qui a la méthode isNull () avec une mauvaise implémentation.

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

Notez que isNull (String str) est une méthode de classe simple, elle ne remplace pas la méthode d'interface. Par exemple, si nous ajoutons une annotation @Override à la méthode isNull (), cela entraînera une erreur de compilation.

Maintenant, lorsque nous exécuterons l'application, nous obtenons la sortie suivante.

Interface Null Check

Impl Null Check

Si nous faisons la méthode d'interface de statique à par défaut, nous obtiendrons la sortie suivante.

Impl Null Check

Impression MyData ::

Impl Null Check

La méthode statique d'interface Java n'est visible que pour les méthodes d'interface, si nous supprimons la méthode isNull () de la classe MyDataImpl, nous ne pourrons pas l'utiliser pour l'objet MyDataImpl. Cependant, comme d'autres méthodes statiques, nous pouvons utiliser des méthodes statiques d'interface en utilisant le nom de classe. Par exemple, une déclaration valide sera:

boolean result = MyData.isNull("abc");

Points importants sur la méthode statique de l'interface java:

  1. La méthode statique de l'interface Java fait partie de l'interface, nous ne pouvons pas l'utiliser pour les objets de classe d'implémentation.
  2. Les méthodes statiques de l'interface Java sont utiles pour fournir des méthodes utilitaires, par exemple la vérification nulle, le tri de collection, etc.
  3. La méthode statique de l'interface Java nous aide à assurer la sécurité en ne permettant pas aux classes d'implémentation de les remplacer.
  4. Nous ne pouvons pas définir de méthode statique d'interface pour les méthodes de classe Object, nous obtiendrons une erreur de compilation comme «Cette méthode statique ne peut pas cacher la méthode d'instance d'Object». C'est parce que ce n'est pas autorisé en java, car Object est la classe de base pour toutes les classes et nous ne pouvons pas avoir une méthode statique au niveau de la classe et une autre méthode d'instance avec la même signature.
  5. Nous pouvons utiliser des méthodes statiques d'interface java pour supprimer des classes utilitaires telles que Collections et déplacer toutes ses méthodes statiques vers l'interface correspondante, ce qui serait facile à trouver et à utiliser.

Interfaces fonctionnelles Java

Avant de conclure le message, je voudrais fournir une brève introduction aux interfaces fonctionnelles. Une interface avec exactement une méthode abstraite est connue sous le nom d'interface fonctionnelle.

Une nouvelle annotation @FunctionalInterfacea été introduite pour marquer une interface comme interface fonctionnelle.@FunctionalInterfacel'annotation est un moyen d'éviter l'ajout accidentel de méthodes abstraites dans les interfaces fonctionnelles. Il est facultatif mais bon de l'utiliser.

Les interfaces fonctionnelles sont une fonctionnalité attendue depuis longtemps et très recherchée de Java 8 car elle nous permet d'utiliser des expressions lambda pour les instancier. Un nouveau package java.util.function avec un tas d'interfaces fonctionnelles est ajouté pour fournir des types cibles pour les expressions lambda et les références de méthode. Nous étudierons les interfaces fonctionnelles et les expressions lambda dans les prochains articles.

Emplacement des ressources:

  1. Modifications de l'interface Java 8 - méthode statique, méthode par défaut
SkyWalker
la source
8
Je recherche exactement ces types de réponses mises à jour. Merci pour la réponse rapide.
Ravindra babu
41

Toutes vos déclarations sont valables à l'exception de votre première déclaration (après la version Java 8):

Les méthodes d'une interface Java sont implicitement abstraites et ne peuvent pas avoir d'implémentations

Depuis la page de documentation :

Une interface est un type de référence, similaire à une classe, qui ne peut contenir que des constantes, des signatures de méthode, des méthodes par défaut, des méthodes statiques et des types imbriqués

Les corps de méthode existent uniquement pour les méthodes par défaut et les méthodes statiques.

Méthodes par défaut:

Une interface peut avoir des méthodes par défaut , mais sont différentes des méthodes abstraites dans les classes abstraites.

Les méthodes par défaut vous permettent d'ajouter de nouvelles fonctionnalités aux interfaces de vos bibliothèques et d'assurer la compatibilité binaire avec le code écrit pour les anciennes versions de ces interfaces.

Lorsque vous étendez une interface qui contient une méthode par défaut, vous pouvez effectuer les opérations suivantes:

  1. Sans mentionner la méthode par défaut, ce qui permet à votre interface étendue d'hériter de la méthode par défaut.
  2. Redéclarez la méthode par défaut, ce qui la rend abstract .
  3. Redéfinissez la méthode par défaut, qui la remplace.

Méthodes statiques:

En plus des méthodes par défaut, vous pouvez définir des méthodes statiques dans les interfaces. (Une méthode statique est une méthode associée à la classe dans laquelle elle est définie plutôt qu'à tout objet. Chaque instance de la classe partage ses méthodes statiques.)

Cela vous permet d'organiser plus facilement les méthodes d'assistance dans vos bibliothèques;

Exemple de code de la page de documentation sur les méthodes et interfaceavoir .staticdefault

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

Utilisez les instructions ci-dessous pour choisir d'utiliser une interface ou une classe abstraite.

Interface:

  1. Pour définir un contrat (de préférence apatride - je veux dire pas de variables)
  2. Pour lier des classes sans rapport avec a des capacités.
  3. Pour déclarer des variables constantes publiques ( état immuable )

Classe abstraite:

  1. Partagez le code entre plusieurs classes étroitement liées. Elle établit une relation.

  2. Partager l'état commun entre les classes liées (l'état peut être modifié dans des classes concrètes)

Articles Similaires:

Interface vs classe abstraite (OO général)

Implémente vs étend: Quand l'utiliser? Quelle est la différence?

En parcourant ces exemples, vous pouvez comprendre que

Les classes non liées peuvent avoir des capacités via l'interface, mais les classes liées modifient le comportement par l'extension des classes de base.

Ravindra babu
la source
Que voulez-vous dire par «contrat apatride»? C'est le point 1 sur les interfaces
Maksim Dmitriev
1
Absence d'état mutable. Puisque l'interface peut avoir des constantes, les données peuvent être mutées contrairement aux classes abstraites
Ravindra babu
1
Correction dans l'énoncé ci-dessus. Dans l'interface, les données ne peuvent pas être mutées contrairement à la classe abstraite
Ravindra babu
2
C'est la meilleure réponse. Non seulement il s'adresse à Java8, mais il explique également dans quelles situations particulières vous utiliseriez l'un ou l'autre.
Shuklaswag
Le concept d' statelessinterface est un joli succès. L'interface ne peut avoir aucun état (l'interface peut avoir des constantes mais elles sont finales / statiques donc immuables).
Kaihua
22

Votre explication semble décente, mais peut-être semble-t-il que vous lisiez tout cela dans un manuel? : - /

Ce qui me dérange le plus, c'est à quel point votre exemple était solide? Avez-vous pris la peine d'inclure presque toutes les différences entre l'abstrait et les interfaces?

Personnellement, je suggère ce lien: http://mindprod.com/jgloss/interfacevsabstract.html#TABLE

pour une liste exhaustive des différences ..

J'espère que cela vous aidera, vous et tous les autres lecteurs, dans leurs futures interviews

VictorCreator
la source
1
le lien est partagé est vraiment génial
Premraj
Vous pouvez fournir une implémentation par défaut dans les interfaces java en utilisant le mot clé par défaut
Ogen
21

De nombreux développeurs juniors font l'erreur de considérer les interfaces, les classes abstraites et concrètes comme de légères variations de la même chose, et choisissent l'une d'entre elles uniquement pour des raisons techniques: ai-je besoin d'un héritage multiple? Ai-je besoin d'un endroit pour mettre des méthodes communes? Dois-je m'embêter avec autre chose qu'un cours concret? C'est faux, et le problème principal est caché dans ces questions: "Je" . Lorsque vous écrivez du code pour vous-même, vous pensez rarement à d'autres développeurs actuels ou futurs travaillant sur ou avec votre code.

Les interfaces et les classes abstraites, bien qu'apparemment similaires d'un point de vue technique, ont des significations et des objectifs complètement différents.

Sommaire

  1. Une interface définit un contrat qu'une certaine implémentation remplira pour vous .

  2. Une classe abstraite fournit un comportement par défaut que votre implémentation peut réutiliser.

Ces deux points ci-dessus sont ce que je recherche lors d'un entretien, et c'est un résumé assez compact. Lire la suite pour plus de détails.

Résumé alternatif

  1. Une interface permet de définir des API publiques
  2. Une classe abstraite est à usage interne et pour définir des SPI

Par exemple

En d'autres termes: une classe concrète fait le travail réel, d'une manière très spécifique. Par exemple, un utilise des nœuds à double liaison pour stocker une liste d'objets, qui offre à la place une itération rapide, des modifications sur place et une insertion / suppression / addition, mais est terrible à l'accès aléatoire. Ces deux types de listes sont optimisés pour différents cas d'utilisation, et la façon dont vous allez les utiliser importe beaucoup. Lorsque vous essayez d'extraire les performances d'une liste avec laquelle vous interagissez fortement, et lorsque vous choisissez le type de liste, vous devez soigneusement choisir celle que vous instanciez.ArrayList utilise une zone de mémoire contiguë pour stocker une liste d'objets de manière compacte qui offre un accès aléatoire rapide, une itération et des modifications sur place, mais est terrible lors des insertions, des suppressions et parfois même des ajouts; pendant ce temps, unLinkedList

D'un autre côté, les utilisateurs de haut niveau d'une liste ne se soucient pas vraiment de la façon dont elle est réellement mise en œuvre, et ils doivent être isolés de ces détails. Imaginons que Java n'ait pas exposé l' Listinterface, mais n'avait qu'une Listclasse concrète qui est en fait ce qui LinkedListest en ce moment. Tous les développeurs Java auraient adapté leur code pour s'adapter aux détails de l'implémentation: éviter l'accès aléatoire, ajouter un cache pour accélérer l'accès, ou simplement réimplémenter ArrayListpar eux-mêmes, bien qu'il soit incompatible avec tous les autres codes qui ne fonctionnent qu'avec List. Ce serait terrible ... Mais imaginez maintenant que les maîtres Java réalisent réellement qu'une liste chaînée est terrible pour la plupart des cas d'utilisation réels, et ont décidé de passer à une liste de tableaux pour leur seulListclasse disponible. Cela affecterait les performances de chaque programme Java dans le monde, et les gens n'en seraient pas satisfaits. Et le principal coupable est que les détails de l'implémentation étaient disponibles, et les développeurs ont supposé que ces détails étaient un contrat permanent sur lequel ils pouvaient s'appuyer. C'est pourquoi il est important de masquer les détails de l'implémentation et de définir uniquement un contrat abstrait. C'est le but d'une interface: définir le type d'entrée qu'une méthode accepte et le type de sortie attendu, sans exposer tous les tripes qui inciteraient les programmeurs à modifier leur code pour s'adapter aux détails internes qui pourraient changer avec toute mise à jour future .

Une classe abstraite se situe entre les interfaces et les classes concrètes. Il est censé aider les implémentations à partager du code commun ou ennuyeux. Par exemple, AbstractCollectionfournit des implémentations de isEmptybase pour basées sur la taille est 0, containscomme itérer et comparer, addAllcomme répété add, et ainsi de suite. Cela permet aux implémentations de se concentrer sur les parties cruciales qui les différencient: comment réellement stocker et récupérer des données.

Autre perspective: API versus SPI

Les interfaces sont des passerelles à faible cohésion entre différentes parties du code. Ils permettent aux bibliothèques d'exister et d'évoluer sans casser chaque utilisateur de bibliothèque lorsque quelque chose change en interne. C'est ce qu'on appelle l' interface de programmation d'application , pas les classes de programmation d'application. À plus petite échelle, ils permettent également à plusieurs développeurs de collaborer avec succès sur des projets à grande échelle, en séparant différents modules via des interfaces bien documentées.

Les classes abstraites sont des aides à haute cohésion à utiliser lors de l'implémentation d'une interface, en supposant un certain niveau de détails d'implémentation. Alternativement, des classes abstraites sont utilisées pour définir des SPI, des interfaces de fournisseur de services.

La différence entre une API et un SPI est subtile, mais importante: pour une API, l'accent est mis sur qui l' utilise et pour un SPI, l'accent est mis sur qui l' implémente .

L'ajout de méthodes à une API est facile, tous les utilisateurs existants de l'API seront toujours compilés. L'ajout de méthodes à un SPI est difficile, car chaque fournisseur de services (implémentation concrète) devra implémenter les nouvelles méthodes. Si des interfaces sont utilisées pour définir un SPI, un fournisseur devra publier une nouvelle version chaque fois que le contrat SPI change. Si des classes abstraites sont utilisées à la place, de nouvelles méthodes pourraient être définies en termes de méthodes abstraites existantes, ou en tant que throw not implemented exceptionstubs vides , ce qui permettra au moins à une ancienne version d'une implémentation de service de se compiler et de s'exécuter.

Une note sur Java 8 et les méthodes par défaut

Bien que Java 8 ait introduit des méthodes par défaut pour les interfaces, ce qui rend la ligne entre les interfaces et les classes abstraites encore plus floue, ce n'était pas pour que les implémentations puissent réutiliser le code, mais pour faciliter la modification des interfaces qui servent à la fois d'API et de SPI (ou sont mal utilisés pour définir des SPI au lieu de classes abstraites).

"Connaissance du livre"

Les détails techniques fournis dans la réponse du PO sont considérés comme des "connaissances du livre" car c'est généralement l'approche utilisée à l'école et dans la plupart des livres de technologie sur une langue: ce qu'est une chose, pas comment l' utiliser dans la pratique, en particulier dans les applications à grande échelle .

Voici une analogie: supposé que la question était:

Quoi de mieux pour louer pour une nuit de bal, une voiture ou une chambre d'hôtel?

La réponse technique ressemble à:

Eh bien, dans une voiture, vous pouvez le faire plus tôt, mais dans une chambre d'hôtel, vous pouvez le faire plus confortablement. D'un autre côté, la chambre d'hôtel est à un seul endroit, tandis que dans la voiture, vous pouvez le faire dans plus d'endroits, comme, disons que vous pouvez aller au point de vue pour une belle vue, ou dans un cinéma en plein air, ou bien d'autres endroits, ou même dans plus d'un endroit. De plus, la chambre d'hôtel dispose d'une douche.

C'est vrai, mais il manque complètement les points qu'il s'agit de deux choses complètement différentes, et les deux peuvent être utilisées en même temps à des fins différentes, et l'aspect "le faire" n'est pas la chose la plus importante à propos de l'une ou l'autre des deux options . La réponse manque de perspective, elle montre une façon de penser immature, tout en présentant correctement les vrais "faits".

Sergiu Dumitriu
la source
Voulez-vous dire "low-coupling"?
user2418306
@ user2418306 Non, la cohésion est un terme plus générique qui inclut le couplage, bien qu'ils soient des synonymes proches, et l'un ou l'autre terme aurait fonctionné.
Sergiu Dumitriu
9

Qu'en est-il de penser de la manière suivante:

  • Une relation entre une classe et une classe abstraite est de type "is-a"
  • Une relation entre une classe et une interface est de type "has-a"

Donc, quand vous avez une classe abstraite Mammifères, une sous-classe Humaine et une interface Conduite, alors vous pouvez dire

  • chaque humain est un mammifère
  • chaque humain a une conduite (comportement)

Ma suggestion est que la phrase de connaissance du livre indique qu'il voulait entendre la différence sémantique entre les deux (comme d'autres l'ont déjà suggéré ici).

akohout
la source
9

Une interface est un "contrat" ​​où la classe qui implémente le contrat promet d'implémenter les méthodes. Un exemple où j'ai dû écrire une interface au lieu d'une classe était quand je mettais à jour un jeu de 2D à 3D. J'ai dû créer une interface pour partager des cours entre la version 2D et la version 3D du jeu.

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

Ensuite, je peux implémenter les méthodes basées sur l'environnement, tout en étant capable d'appeler ces méthodes à partir d'un objet qui ne sait pas quelle version du jeu se charge.

public class Adventure extends JFrame implements Playable

public class Dungeon3D extends SimpleApplication implements Playable

public class Main extends SimpleApplication implements AnimEventListener, ActionListener, Playable

En règle générale, dans le monde du jeu, le monde peut être une classe abstraite qui exécute des méthodes sur le jeu:

public abstract class World...

    public Playable owner;

    public Playable getOwner() {
        return owner;
    }

    public void setOwner(Playable owner) {
        this.owner = owner;
    }
Niklas R.
la source
6

Les classes abstraites ne sont pas de l'abstraction pure, car sa collection de méthodes concrètes (implémentées) et non implémentées. Mais les interfaces sont une pure abstraction car il n'existe que des méthodes non implémentées et non des méthodes concrètes.

Pourquoi des classes abstraites?

  1. Si l'utilisateur souhaite écrire des fonctionnalités communes à tous les objets.
  2. Les classes abstraites sont le meilleur choix pour la réimplémentation à l'avenir que pour ajouter plus de fonctionnalités sans affecter l'utilisateur final.

Pourquoi des interfaces?

  1. Si l'utilisateur souhaite écrire des fonctionnalités différentes, ce serait une fonctionnalité différente sur les objets.
  2. Les interfaces sont le meilleur choix qui, si ce n'est pas besoin de modifier les exigences une fois que l'interface a été publiée.
Sarfaraz Ahamad
la source
5

Une interface est comme un ensemble de gènes qui sont publiquement documentés pour avoir une sorte d'effet: un test ADN me dira si je les ai - et si je le fais, je peux faire savoir publiquement que je suis un "porteur" "et une partie de mon comportement ou de mon état s'y conformera. (Mais bien sûr, je peux avoir de nombreux autres gènes qui fournissent des traits hors de cette portée.)

Une classe abstraite est comme l'ancêtre mort d'une espèce de sexe unique (*): elle ne peut pas être vivifiée mais vivante (c'est -à- dire non abstraite descendant ) hérite de tous ses gènes.

(*) Pour étirer cette métaphore, disons que tous les membres de l'espèce vivent au même âge. Cela signifie que tous les ancêtres d'un ancêtre mort doivent également être morts - et de même, tous les descendants d'un ancêtre vivant doivent être vivants.

Steve Chambers
la source
4

Je fais des entretiens pour le travail et je regarderais aussi défavorablement votre réponse (désolé mais je suis très honnête). Il semble que vous ayez lu la différence et révisé une réponse, mais vous ne l'avez peut-être jamais utilisé dans la pratique.

Une bonne explication de la raison pour laquelle vous utiliseriez chacun peut être bien meilleure que d'avoir une explication précise de la différence. Les employeurs veulent ultimement que les programmeurs fassent des choses qu'ils ne connaissent pas, ce qui peut être difficile à démontrer lors d'une entrevue. La réponse que vous avez donnée serait bonne si vous postulez pour un emploi technique ou basé sur la documentation, mais pas pour un rôle de développeur.

Bonne chance avec des interviews à l'avenir.

De plus, ma réponse à cette question concerne davantage la technique d'entrevue que le matériel technique que vous avez fourni. Pensez peut-être à lire à ce sujet. https://workplace.stackexchange.com/ peut être un excellent endroit pour ce genre de chose.

Adrian
la source
1
Pourriez-vous me dire comment vous y avez répondu? Peut-être que cela peut m'aider.
code_fish
vous donner la réponse en offre beaucoup moins que de vous aider à le résoudre, donnez essentiellement un exemple pratique du moment où vous les utiliseriez et expliquez pourquoi chacun est adapté aux différentes tâches.
Adrian
4

Vous choisissez Interface en Java pour éviter le problème Diamond dans l'héritage multiple .

Si vous souhaitez que toutes vos méthodes soient implémentées par votre client, optez pour l'interface. Cela signifie que vous concevez l'intégralité de l'application sur abstract.

Vous choisissez la classe abstraite si vous savez déjà ce qui est commun. Par exemple, prenez un cours abstrait Car. À un niveau supérieur, vous implémentez les méthodes de voiture courantes comme calculateRPM(). C'est une méthode courante et vous laissez le client implémenter son propre comportement comme
calculateMaxSpeed()etc. Vous auriez probablement expliqué en donnant quelques exemples en temps réel que vous avez rencontrés dans votre travail quotidien.

MaheshVarma
la source
3

La principale différence que j'ai observée est que la classe abstraite nous fournit un comportement commun déjà implémenté et que les sous-classes n'ont besoin que d'implémenter des fonctionnalités spécifiques qui leur correspondent. où, comme pour une interface, ne précisera que les tâches à effectuer et aucune implémentation ne sera donnée par l'interface. Je peux dire qu'il spécifie le contrat entre lui-même et les classes implémentées.


la source
3

Même moi, j'ai été confronté à la même question dans plusieurs interviews et croyez-moi, cela rend votre temps misérable pour convaincre l'intervieweur. Si j'inhérente à toutes les réponses ci-dessus, je dois ajouter un point clé de plus pour le rendre plus convaincant et utiliser OO à son meilleur.

Dans le cas où vous ne prévoyez pas de modification des règles , pour la sous-classe à suivre, pour un long avenir, optez pour l'interface, car vous ne pourrez pas y modifier et si vous le faites, vous devez opter pour le changements dans toutes les autres sous-classes, alors que, si vous pensez, vous voulez réutiliser la fonctionnalité, définir certaines règles et la rendre ouverte à la modification , optez pour la classe Abstract.

Pensez de cette façon, vous avez utilisé un service de consommables ou vous avez fourni du code au monde et vous avez la possibilité de modifier quelque chose, supposez un contrôle de sécurité Et si je suis un consommateur du code et Un matin après une mise à jour, je trouver toutes les marques de lecture dans mon Eclipse, toute l'application est en panne. Donc, pour éviter de tels cauchemars, utilisez Résumé sur les interfaces

Je pense que cela pourrait convaincre l'enquêteur dans une certaine mesure ... Bonne entrevues à venir.

vinod bazari
la source
2

Lorsque j'essaie de partager le comportement entre 2 classes étroitement liées, je crée une classe abstraite qui détient le comportement commun et sert de parent aux deux classes.

Lorsque j'essaie de définir un type, une liste de méthodes qu'un utilisateur de mon objet peut invoquer de manière fiable, je crée une interface.

Par exemple, je ne créerais jamais une classe abstraite avec 1 sous-classe concrète car les classes abstraites concernent le partage des comportements. Mais je pourrais très bien créer une interface avec une seule implémentation. L'utilisateur de mon code ne saura pas qu'il n'y a qu'une seule implémentation. En effet, dans une future version, il peut y avoir plusieurs implémentations, qui sont toutes des sous-classes d'une nouvelle classe abstraite qui n'existaient même pas lorsque j'ai créé l'interface.

Cela aurait pu sembler un peu trop livresque aussi (même si je ne l'ai jamais vu s'exprimer ainsi partout où je me souviens). Si l'intervieweur (ou l'OP) voulait vraiment plus de mon expérience personnelle à ce sujet, j'aurais été prêt avec des anecdotes d'une interface qui a évolué par nécessité et vice versa.

Encore une chose. Java 8 vous permet désormais de mettre du code par défaut dans une interface, brouillant davantage la frontière entre les interfaces et les classes abstraites. Mais d'après ce que j'ai vu, cette fonctionnalité est surutilisée même par les créateurs des bibliothèques de base Java. Cette fonctionnalité a été ajoutée, à juste titre, pour permettre d'étendre une interface sans créer d'incompatibilité binaire. Mais si vous créez un tout nouveau type en définissant une interface, alors l'interface devrait être JUSTE une interface. Si vous souhaitez également fournir du code commun, créez par tous les moyens une classe d'assistance (abstraite ou concrète). N'encombrez pas votre interface depuis le début avec des fonctionnalités que vous voudrez peut-être modifier.

Teto
la source
2

La différence de base entre l'interface et la classe abstraite est que l'interface prend en charge l'héritage multiple mais pas la classe abstraite.

Dans la classe abstraite, vous pouvez également fournir toutes les méthodes abstraites comme l'interface.

pourquoi la classe abstraite est requise?

Dans certains scénarios, lors du traitement de la demande de l'utilisateur, la classe abstraite ne sait pas quelle intention de l'utilisateur. Dans ce scénario, nous définirons une méthode abstraite dans la classe et demanderons à l'utilisateur qui étend cette classe, veuillez indiquer votre intention dans la méthode abstraite. Dans ce cas, les classes abstraites sont très utiles

Pourquoi une interface est-elle requise?

Disons que j'ai un travail que je n'ai pas d'expérience dans ce domaine. Par exemple, si vous voulez construire un bâtiment ou un barrage, que ferez-vous dans ce scénario?

  1. vous identifierez quelles sont vos exigences et conclurez un contrat avec ces exigences.
  2. Appelez ensuite les appels d'offres pour construire votre projet
  3. Qui a jamais construit le projet, qui devrait répondre à vos besoins. Mais la logique de construction est différente d'un fournisseur à l'autre.

Ici, je ne me soucie pas de la façon dont ils ont construit. L'objet final a satisfait ou non mes exigences, c'est seulement mon point clé.

Ici, vos exigences appelées interface et constructeurs sont appelées implémenteur.

Dharisi Suresh
la source
2

En quelques mots, je répondrais de cette façon:

  • l'héritage via la hiérarchie des classes implique un héritage d'état ;
  • considérant que l'héritage via les interfaces signifie l'héritage du comportement ;

Les classes abstraites peuvent être traitées comme quelque chose entre ces deux cas (cela introduit un certain état mais vous oblige également à définir un comportement), une classe entièrement abstraite est une interface (il s'agit d'un développement ultérieur de classes constituées de méthodes virtuelles uniquement en C ++ comme autant que je sache sa syntaxe).

Bien sûr, à partir de Java 8, les choses ont légèrement changé, mais l'idée est toujours la même.

Je suppose que c'est assez pour une interview Java typique, si vous n'êtes pas interviewé par une équipe de compilation.

Gleb Stromov
la source
1

D'après ce que je comprends, une interface, qui est composée de variables finales et de méthodes sans implémentations, est implémentée par une classe pour obtenir un groupe de méthodes ou de méthodes qui sont liées les unes aux autres. D'un autre côté, une classe abstraite, qui peut contenir des variables et des méthodes non finales avec des implémentations, est généralement utilisée comme guide ou comme super-classe dont toutes les classes apparentées ou similaires héritent. En d'autres termes, une classe abstraite contient toutes les méthodes / variables qui sont partagées par toutes ses sous-classes.

Marz
la source
1

En classe abstraite, vous pouvez écrire l'implémentation par défaut des méthodes! Mais dans Interface, vous ne pouvez pas. Fondamentalement, dans l'interface, il existe des méthodes virtuelles pures qui doivent être implémentées par la classe qui implémente l'interface.

dg_no_9
la source
1

Oui, vos réponses étaient techniquement correctes, mais là où vous vous êtes trompé, vous ne leur montriez pas que vous compreniez les avantages et les inconvénients de choisir l'un plutôt que l'autre. En outre, ils étaient probablement préoccupés / paniqués par la compatibilité de leur base de code avec les mises à niveau à l'avenir. Ce type de réponse a peut-être aidé (en plus de ce que vous avez dit):

"Le choix d'une classe abstraite par rapport à une classe d'interface dépend de ce que nous prévoyons de l'avenir du code.

Les classes abstraites permettent une meilleure compatibilité ascendante car vous pouvez continuer à ajouter du comportement à une classe abstraite dans le futur sans casser votre code existant -> ce n'est pas possible avec une classe d'interface.

D'un autre côté, les classes d'interface sont plus flexibles que les classes abstraites. En effet, ils peuvent implémenter plusieurs interfaces . Le fait est que Java n'a pas plusieurs héritages, donc l'utilisation de classes abstraites ne vous permettra pas d'utiliser une autre structure de hiérarchie de classe ...

Donc, à la fin, une bonne règle générale est la suivante: préférez utiliser les classes d'interface lorsqu'il n'y a pas d'implémentations existantes / par défaut dans votre base de code. Et, utilisez les classes abstraites pour préserver la compatibilité si vous savez que vous mettrez à jour votre classe à l'avenir. "

Bonne chance pour votre prochaine interview!

Jaxian
la source
1

Je vais essayer de répondre en utilisant un scénario pratique pour montrer la distinction entre les deux.

Les interfaces sont livrées avec une charge utile nulle, c'est-à-dire qu'aucun état ne doit être maintenu et sont donc un meilleur choix pour simplement associer un contrat (capacité) à une classe.

Par exemple, disons que j'ai une classe Task qui exécute une action, maintenant pour exécuter une tâche dans un thread séparé, je n'ai pas vraiment besoin d'étendre la classe Thread. ), puis passez l'objet de cette classe Task à une instance de thread et appelez sa méthode start ().

Vous pouvez maintenant vous demander si Runnable était une classe abstraite?

Eh bien, techniquement, c'était possible, mais au niveau de la conception, cela aurait été un mauvais choix étant:

  • Runnable n'a aucun état qui lui est associé et il n'offre aucune implémentation par défaut pour la méthode run ()
  • La tâche devrait l'étendre ainsi elle ne pourrait étendre aucune autre classe
  • La tâche n'a rien à offrir en tant que spécialisation à la classe Runnable, il suffit de remplacer la méthode run ()

En d'autres termes, la classe Task avait besoin d'une capacité à exécuter dans un thread, ce qu'elle a obtenu en implémentant des versets d'interface Runnable étendant la classe Thread qui en ferait un thread.

Mettez-nous simplement une interface pour définir une capacité (contrat), tout en utilisant une classe abstraite pour en définir l'implémentation squelette (commune / partielle).

Avertissement: un exemple stupide suit, essayez de ne pas juger :-P

interface Forgiver {
    void forgive();
}

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

Maintenant, on vous a donné le choix d’être semblable à Dieu, mais vous pouvez choisir d’être Pardonneur uniquement (c’est-à-dire pas semblable à Dieu) et de faire:

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

Ou vous pouvez choisir d'être comme Dieu et faire:

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

PS avec interface java 8 peut également avoir des méthodes statiques ainsi que par défaut (implémentation redéfinissable) et donc l'interface différence n / b et la classe abstraite sont encore plus restreintes.

sactiw
la source
1

Presque tout semble déjà être couvert ici .. Ajout d'un autre point sur la mise en œuvre pratique de la abstractclasse:

abstractLe mot clé est également utilisé pour empêcher une classe d'être instanciée. Si vous avez une classe concrète que vous ne voulez pas instancier - Faites-la abstract.

Lame
la source
1

hmm maintenant les gens ont faim approche pratique, vous avez tout à fait raison mais la plupart des enquêteurs regardent selon leurs exigences actuelles et veulent une approche pratique.

après avoir terminé votre réponse, vous devriez sauter sur l'exemple:

Abstrait:

par exemple, nous avons une fonction de salaire qui a des paramètres communs à tous les employés. Ensuite, nous pouvons avoir une classe abstraite appelée CTC avec un corps de méthode partiellement défini et elle sera étendue par tous les types d'employés et redéfinie selon leurs capacités supplémentaires. Pour la fonctonalité commune.

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
{   
}

Interface

l'interface en java permet d'avoir des fonctionnalités interfcae sans étendre celle-ci et il faut être clair avec l'implémentation de la signature des fonctionnalités que l'on souhaite introduire dans son application. cela vous obligera à avoir une définition. Pour différentes fonctionnalités.

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

}

vous pouvez aussi avoir une telle activité forcée avec une classe abstraite par des méthgos définis comme abstraits, maintenant une classe qui étend la classe abstraite remin abstraite jusqu'à ce qu'elle écrase cette fonction abstraite.

RTA
la source
1

D'après ce que je comprends et comment j'approche,

L'interface est comme une spécification / contrat, toute classe qui implémente une classe d'interface doit implémenter toutes les méthodes définies dans la classe abstraite (sauf les méthodes par défaut (introduites dans Java 8))

Alors que je définis un résumé de classe quand je connais l'implémentation requise pour certaines méthodes de la classe et certaines méthodes, je ne sais toujours pas quelle sera l'implémentation (nous pouvons connaître la signature de la fonction mais pas l'implémentation). Je le fais pour que plus tard dans la partie du développement, quand je saurai comment ces méthodes doivent être implémentées, je puisse simplement étendre cette classe abstraite et implémenter ces méthodes.

Remarque: Vous ne pouvez pas avoir de corps de fonction dans les méthodes d'interface sauf si la méthode est statique ou par défaut.

Akash Lodha
la source
0

Je crois que l'intervieweur essayait de comprendre la différence entre l'interface et la mise en œuvre.

L'interface - pas une interface Java, mais «interface» en termes plus généraux - avec un module de code est, fondamentalement, le contrat conclu avec le code client qui utilise l'interface.

L'implémentation d'un module de code est le code interne qui fait fonctionner le module. Souvent, vous pouvez implémenter une interface particulière de plusieurs manières différentes et même modifier l'implémentation sans que le code client ne soit au courant du changement.

Une interface Java ne doit être utilisée qu'en tant qu'interface dans le sens générique ci-dessus, pour définir comment la classe se comporte au profit du code client utilisant la classe, sans spécifier aucune implémentation. Ainsi, une interface comprend des signatures de méthode - les noms, les types de retour et les listes d'arguments - pour les méthodes censées être appelées par le code client, et devrait en principe avoir beaucoup de Javadoc pour chaque méthode décrivant ce que fait cette méthode. La raison la plus convaincante d'utiliser une interface est que vous prévoyez d'avoir plusieurs implémentations différentes de l'interface, peut-être en sélectionnant une implémentation en fonction de la configuration de déploiement.

Une classe abstraite Java, en revanche, fournit une implémentation partielle de la classe, plutôt que d'avoir un objectif principal de spécifier une interface. Il doit être utilisé lorsque plusieurs classes partagent du code, mais lorsque les sous-classes sont également censées fournir une partie de l'implémentation. Cela permet au code partagé d'apparaître en un seul endroit - la classe abstraite - tout en précisant que des parties de l'implémentation ne sont pas présentes dans la classe abstraite et devraient être fournies par des sous-classes.

Warren Dew
la source
0

votre réponse est juste, mais l'intervieweur a besoin de vous pour différencier selon la perspective de l'ingénierie logicielle et non selon les détails de Java.

Mots simples:

Une interface est comme l'interface d'une boutique, tout ce qui y est affiché devrait être là dans la boutique, donc toute méthode dans l'interface doit être implémentée dans la classe concrète. Maintenant, que se passe-t-il si certaines classes partagent certaines méthodes exactes et varient dans d'autres. Supposons que l'Interface concerne un magasin qui contient deux choses et supposons que nous avons deux magasins qui contiennent tous les deux des équipements de sport, mais l'un a des vêtements supplémentaires et l'autre des chaussures supplémentaires. Donc ce que vous faites est de créer une classe abstraite pour le sport qui implémente la méthode Sports et laisse l'autre méthode non implémentée. La classe abstraite signifie ici que cette boutique n'existe pas elle-même mais c'est la base pour d'autres classes / boutiques. De cette façon, vous organisez le code, évitez les erreurs de réplication du code, unifiez le code et garantissez la réutilisation par une autre classe.

Mosab Shaheen
la source