web-dev-qa-db-fra.com

Pourquoi une classe abstraite implémentant une interface peut manquer la déclaration / implémentation d'une des méthodes de l'interface?

Une chose curieuse se passe dans Java lorsque vous utilisez une classe abstraite pour implémenter une interface: certaines méthodes de l'interface peuvent être complètement absentes (c'est-à-dire qu'il n'y a pas de déclaration abstraite ou d'implémentation réelle), mais le compilateur ne se plaint pas.

Par exemple, étant donné l'interface:

public interface IAnything {
  void m1();
  void m2();
  void m3();
}

la classe abstraite suivante est joyeusement compilée sans avertissement ni erreur:

public abstract class AbstractThing implements IAnything {
  public void m1() {}
  public void m3() {}
}

Pouvez-vous expliquer pourquoi?

120

En effet, si une classe est abstraite, vous devez par définition en créer des sous-classes pour instancier. Les sous-classes seront nécessaires (par le compilateur) pour implémenter les méthodes d'interface laissées par la classe abstraite.

En suivant votre exemple de code, essayez de créer une sous-classe de AbstractThing sans implémenter le m2 et voyez quelles erreurs le compilateur vous a données. Cela vous obligera à implémenter cette méthode.

150
Bill the Lizard

Parfaitement bien.
Vous ne pouvez pas instancier des classes abstraites .. mais des classes abstraites peuvent être utilisées pour héberger des implémentations communes pour m1 () et m3 ().
Donc si la mise en œuvre de m2 () est différente pour chaque mise en oeuvre, mais que m1 et m3 ne le sont pas. Vous pouvez créer différentes implémentations IAnything concrètes avec uniquement l'implémentation m2 différente et dériver de AbstractThing - respectant le principe DRY. Valider si l'interface est complètement implémentée pour une classe abstraite est futile ..

Mise à jour: Fait intéressant, je trouve que C # applique cela comme une erreur de compilation. Dans ce scénario, vous devez obligatoirement copier les signatures de méthode et les préfixer par 'public abstrait' dans la classe de base abstraite. (Quelque chose de nouveau tous les jours :)

33
Gishu

C'est très bien. Pour comprendre ce qui précède, vous devez d’abord comprendre la nature des classes abstraites. Ils sont similaires aux interfaces à cet égard. C’est ce que dit Oracle à ce sujet ici .

Les classes abstraites sont similaires aux interfaces. Vous ne pouvez pas les instancier, et elles peuvent contenir un mélange de méthodes déclarées avec ou sans implémentation.

Vous devez donc penser à ce qui se passe quand une interface étend une autre interface. Par exemple ...

//Filename: Sports.Java
public interface Sports
{
   public void setHomeTeam(String name);
   public void setVisitingTeam(String name);
}

//Filename: Football.Java
public interface Football extends Sports
{
   public void homeTeamScored(int points);
   public void visitingTeamScored(int points);
   public void endOfQuarter(int quarter);
}

... comme vous pouvez le constater, cela compile parfaitement. Tout simplement parce que, tout comme une classe abstraite, une interface ne peut PAS être instanciée. Il n'est donc pas nécessaire de mentionner explicitement les méthodes à partir de son "parent". Cependant, TOUTES les signatures de méthodes parent DOIVENT faire implicitement partie de l'interface d'extension ou de la classe abstraite d'implémentation. Ainsi, une fois qu'une classe appropriée (pouvant être instanciée) étend ce qui précède, il sera nécessaire de s'assurer que chaque méthode abstraite est implémentée.

Espérons que cela aide ... et Allahu 'alam!

7
Grateful

Interface signifie une classe qui n'a pas d'implémentation de sa méthode, mais avec juste une déclaration.
D'autre part, la classe abstraite est une classe qui peut avoir une implémentation d'une méthode avec une méthode avec déclaration, sans implémentation.
Lorsque nous implémentons une interface dans une classe abstraite, cela signifie que la classe abstraite a hérité de toutes les méthodes de l'interface. Comme il n’est pas important d’implémenter toute la méthode dans une classe abstraite, il s’agit d’une classe abstraite (par héritage également), de sorte que la classe abstraite peut laisser une partie de la méthode dans l’interface sans implémentation ici. Mais, lorsque cette classe abstraite héritera d'une classe concrète, ils devront implémenter toutes ces méthodes non implémentées dans une classe abstraite.

4

Compte tenu de l'interface:

public interface IAnything {
  int i;
  void m1();
  void m2();
  void m3();
}

Voici comment Java le voit réellement:

public interface IAnything {
  public static final int i;
  public abstract void m1();
  public abstract void m2();
  public abstract void m3();
}

Ainsi, vous pouvez laisser certaines (ou toutes) ces méthodes abstract non implémentées, comme vous le feriez dans le cas de abstract classes étendant une autre classe abstract.

Lorsque vous implement et interface, la règle selon laquelle toutes les méthodes interface doivent être implémentées dans la méthode dérivée class ne s'applique qu'au béton class implémentation (ie, qui n'est pas abstract lui-même).

Si vous envisagez en effet de créer un abstract class En dehors de cela, aucune règle n'indique que vous devez implement utiliser toutes les méthodes interface (notez que dans un tel cas, il est obligatoire de déclarer le dérivé class comme abstract)

4
sharhp

Quand une classe abstraite implémente une interface

Dans la section sur les interfaces, il a été noté qu'une classe qui implémente une interface doit implémenter toutes les méthodes de l'interface. Il est toutefois possible de définir une classe qui n'implémente pas toutes les méthodes de l'interface, à condition que la classe soit déclarée abstraite. Par exemple,

abstract class X implements Y {   
    // implements all but one method of Y
}
class XX extends X {   
    // implements the remaining method in Y 
} 

Dans ce cas, la classe X doit être abstraite car elle n'implémente pas entièrement Y, mais la classe XX l'implémente effectivement.

Référence: http://docs.Oracle.com/javase/tutorial/Java/IandI/abstract.html

2
D Vy

Les classes abstraites ne sont pas nécessaires pour implémenter les méthodes. Ainsi, même si elle implémente une interface, les méthodes abstraites de l'interface peuvent rester abstraites. Si vous essayez d'implémenter une interface dans une classe concrète (c'est-à-dire pas abstraite) et que vous n'implémentez pas les méthodes abstraites, le compilateur vous le dira: implémentez les méthodes abstraites ou déclarez la classe abstraite.

1
Vincent Ramdhanie