529 votes

Pourquoi ne puis-je pas définir une méthode statique dans une interface Java ?

EDITAR: À partir de Java 8, les méthodes statiques sont désormais autorisées dans les interfaces.

Voici l'exemple :

public interface IXMLizable<T>
{
  static T newInstanceFromXML(Element e);
  Element toXMLElement();
}

Bien sûr, ça ne marchera pas. Mais pourquoi pas ?

L'un des problèmes possibles serait de savoir ce qui se passe lorsque vous appelez :

IXMLizable.newInstanceFromXML(e);

Dans ce cas, je pense qu'il devrait juste appeler une méthode vide (i.e. {}). Toutes les sous-classes seraient obligées d'implémenter la méthode statique, donc elles seraient toutes en mesure d'appeler la méthode statique. Pourquoi cela n'est-il pas possible ?

EDITAR: Je suppose que je cherche une réponse plus profonde que "parce que c'est comme ça que Java est".

Y a-t-il une raison technologique particulière pour laquelle les méthodes statiques ne peuvent pas être écrasées ? En d'autres termes, pourquoi les concepteurs de Java ont-ils décidé de rendre les méthodes d'instance surmontables, mais pas les méthodes statiques ?

EDITAR: Le problème de ma conception est que j'essaie d'utiliser des interfaces pour faire respecter une convention de codage.

Autrement dit, l'objectif de l'interface est double :

  1. Je veux que l'interface IXMLizable me permette de convertir les classes qui l'implémentent en éléments XML (en utilisant le polymorphisme, cela fonctionne bien).

  2. Si quelqu'un veut créer une nouvelle instance d'une classe qui implémente l'interface IXMLizable, il saura toujours qu'il existe un constructeur statique newInstanceFromXML(Element e).

Existe-t-il un autre moyen de s'en assurer, autre que de mettre un commentaire dans l'interface ?

4 votes

Il n'est pas nécessaire d'encombrer les définitions de méthodes (et de champs) de public dans les interfaces, d'ailleurs.

0 votes

Hmm, il semble qu'il s'agisse d'un doublon de stackoverflow.com/questions/21817/ . Je n'avais pas vu ça avant.

1 votes

Pourriez-vous fournir un code permettant d'utiliser les méthodes de l'interface statique ?

543voto

erickson Points 127945

Java 8 autorise les méthodes d'interface statiques

Avec Java 8, les interfaces puede ont des méthodes statiques. Ils peuvent également avoir des méthodes d'instance concrètes, mais pas de champs d'instance.

Il y a vraiment deux questions ici :

  1. Pourquoi, au bon vieux temps, les interfaces ne pouvaient-elles pas contenir de méthodes statiques ?
  2. Pourquoi les méthodes statiques ne peuvent-elles pas être surchargées ?

Méthodes statiques dans les interfaces

Aucune raison technique solide n'empêchait les interfaces d'avoir des méthodes statiques dans les versions précédentes. Ceci est résumée joliment par l'affiche d'une question dupliquée. Les méthodes d'interface statiques étaient initialement considérées comme un petit changement de langue, et puis il y a eu une proposition officielle pour les ajouter dans Java 7, mais il a été plus tard abandonné en raison de complications imprévues.

Enfin, Java 8 a introduit des méthodes d'interface statiques, ainsi que des méthodes d'instance modifiables avec une implémentation par défaut. Cependant, elles ne peuvent toujours pas avoir de champs d'instance. Ces fonctionnalités font partie de la prise en charge des expressions lambda, et vous pouvez en savoir plus à leur sujet dans Partie H de JSR 335.

Remplacement des méthodes statiques

La réponse à la deuxième question est un peu plus compliquée.

Les méthodes statiques sont résolubles au moment de la compilation. La répartition dynamique est logique pour les méthodes d'instance, lorsque le compilateur ne peut pas déterminer le type concret de l'objet et, par conséquent, ne peut pas résoudre la méthode à invoquer. Mais l'invocation d'une méthode statique nécessite une classe, et puisque cette classe est connue, le compilateur ne peut pas la résoudre. statiquement -au moment de la compilation, la répartition dynamique est inutile.

Il est nécessaire de connaître un peu le fonctionnement des méthodes d'instance pour comprendre ce qui se passe ici. Je suis sûr que la mise en œuvre réelle est très différente, mais laissez-moi vous expliquer ma notion de la répartition des méthodes, qui modélise fidèlement le comportement observé.

Imaginez que chaque classe possède une table de hachage qui associe les signatures de méthodes (nom et types de paramètres) à un morceau de code réel pour implémenter la méthode. Lorsque la machine virtuelle tente d'invoquer une méthode sur une instance, elle interroge l'objet pour connaître sa classe et recherche la signature demandée dans la table de la classe. Si un corps de méthode est trouvé, il est invoqué. Sinon, la classe parente de la classe est obtenue et la recherche y est répétée. L'opération se poursuit jusqu'à ce que la méthode soit trouvée ou qu'il n'y ait plus de classes parentes - ce qui entraîne un message d'erreur NoSuchMethodError .

Si une superclasse et une sous-classe ont toutes deux une entrée dans leurs tables pour la même signature de méthode, la version de la sous-classe est rencontrée en premier, et la version de la superclasse n'est jamais utilisée - il s'agit d'une "surcharge".

Maintenant, supposons que l'on saute l'instance de l'objet et que l'on commence simplement par une sous-classe. La résolution pourrait se faire comme ci-dessus, ce qui vous donnerait une sorte de méthode statique "surchargeable". Cependant, la résolution peut se faire au moment de la compilation, puisque le compilateur part d'une classe connue, plutôt que d'attendre l'exécution pour demander à un objet d'un type non spécifié sa classe. Il n'y a aucun intérêt à "surcharger" une méthode statique puisqu'on peut toujours spécifier la classe qui contient la version désirée.


Constructeur "interfaces

Voici un peu plus de matériel pour répondre à la récente modification de la question.

Il semble que vous souhaitiez imposer une méthode de type constructeur pour chaque mise en œuvre de l'option IXMLizable . Oubliez un instant l'idée d'essayer de faire respecter cette exigence par une interface, et imaginez que vous avez des classes qui répondent à cette exigence. Comment l'utiliseriez-vous ?

class Foo implements IXMLizable<Foo> {
  public static Foo newInstanceFromXML(Element e) { ... }
}

Foo obj = Foo.newInstanceFromXML(e);

Puisque vous devez nommer explicitement le type concret Foo lors de la "construction" du nouvel objet, le compilateur peut vérifier qu'il possède bien la méthode de fabrique nécessaire. Et si ce n'est pas le cas, alors quoi ? Si je peux implémenter un IXMLizable qui n'a pas de "constructeur", et que je crée une instance et que je la passe à votre code, elle es un IXMLizable avec toute l'interface nécessaire.

La construction fait partie de la mise en œuvre, pas l'interface. Tout code qui fonctionne avec succès avec l'interface ne se soucie pas du constructeur. Tout code qui se soucie du constructeur a besoin de connaître le type concret de toute façon, et l'interface peut être ignorée.

0 votes

12 votes

La raison du numéro 1 pourrait-elle être un héritage multiple ? Puisque nous pouvons hériter de plusieurs interfaces, si deux interfaces contiennent la même signature de méthode statique et qu'une classe les implémente toutes les deux et appelle cette méthode, alors les choses pourraient devenir compliquées d'une manière que les créateurs du langage Java ont voulu éviter en interdisant l'héritage multiple de classes en premier lieu. On pourrait évidemment avancer le même argument en faveur de l'interdiction de toute définition de méthode dans les interfaces.

0 votes

Par le même argument, même les constantes de champ devraient être interdites dans les interfaces, mais peut-être que les gérer pour l'héritage multiple n'est pas si compliqué.

52voto

DJClayworth Points 11288

Cette question a déjà été posée et répondue, aquí

Pour dupliquer ma réponse :

Il n'y a jamais d'intérêt à déclarer une méthode statique dans une interface. Elles ne peuvent pas être exécutées par l'appel normal MonInterface.staticMethod(). Si vous les appelez en spécifiant la classe d'implémentation MyImplementor.staticMethod(), vous devez alors connaître la classe réelle, et il importe peu que l'interface la contienne ou non.

Plus important encore, les méthodes statiques ne sont jamais surchargées, et si vous essayez de le faire :

MyInterface var = new MyImplementingClass();
var.staticMethod();

les règles pour static disent que la méthode définie dans le type déclaré de var doit être exécutée. Comme il s'agit d'une interface, c'est impossible.

La raison pour laquelle vous ne pouvez pas exécuter "result=MyInterface.staticMethod()" est qu'il faudrait exécuter la version de la méthode définie dans MyInterface. Mais il ne peut pas y avoir de version définie dans MonInterface, parce que c'est une interface. Elle n'a pas de code par définition.

Bien que vous puissiez dire que cela revient à dire "parce que Java le fait de cette façon", en réalité, cette décision est une conséquence logique d'autres décisions de conception, également prises pour de très bonnes raisons.

15 votes

Si vous utilisez <T extends MyInterface> comme paramètre de type générique, il serait bien de garantir via l'interface que T peut .doSomething().

4 votes

Bien que je comprenne les arguments, je suis d'accord avec @Chris_Betti (même pour les types non génériques) : il serait bien que la structure du code garantisse que certaines classes met en œuvre une API statique spécifique. Peut-être est-ce possible en utilisant un concept différent...

0 votes

@Juh_, .....ou un nouveau mot-clé si cela est absolument nécessaire. Je crois static est un terme minable dans les langues de toute façon, et il a été trop étiré tel quel. Le fait de l'avoir en soi est donc déjà peu convaincant. Voir mon exemple ci-dessus stackoverflow.com/questions/512877/ {Haussement d'épaules.}

38voto

Peter Lawrey Points 229686

Normalement, cela se fait à l'aide du modèle Factory

public interface IXMLizableFactory<T extends IXMLizable> {
  public T newInstanceFromXML(Element e);
}

public interface IXMLizable {
  public Element toXMLElement();
}

7 votes

+1 un modèle d'usine semble être la solution au problème. (mais pas à la question)

0 votes

Quelqu'un peut-il me dire ce que signifie mettre<T extends IXMLizable> ici, je suis nouveau en java, qu'est-ce que cela fait ?

1 votes

@NuwanHarshakumaraPiyarathna T doit être une classe étendant IXMLizable. Regardez dans les génériques Java pour une meilleure compréhension de ce que cela signifie.

21voto

Michael Myers Points 82361

Parce que les méthodes statiques ne peuvent pas être surchargées dans les sous-classes, et donc elles ne peuvent pas être abstraites. Et toutes les méthodes d'une interface le sont, de facto , résumé.

2 votes

Vous pouvez toujours obliger chaque type à implémenter les méthodes des interfaces statiques. Classes de type, tout le monde ?

18 votes

Sortez de vous-même et répondez à la question : Pourquoi Une méthode statique ne peut-elle pas être surchargée ? Si les méthodes statiques pouvaient être surchargées, à quoi cela ressemblerait-il ? Que pourrait-on faire avec elles ? Cette réponse est en gros "Vous ne pouvez pas parce que vous ne pouvez pas".

6voto

tallgirl Points 41

Premièrement, toutes les décisions relatives à la langue sont des décisions prises par les créateurs de la langue. Il n'y a rien dans le monde du génie logiciel, de la définition des langages ou de l'écriture des compilateurs/interprètes qui dise qu'une méthode statique ne peut pas faire partie d'une interface. J'ai créé quelques langages et écrit des compilateurs pour eux - il s'agit simplement de s'asseoir et de définir une sémantique significative. Je dirais que la sémantique d'une méthode statique dans une interface est remarquablement claire, même si le compilateur doit reporter la résolution de la méthode au moment de l'exécution.

Deuxièmement, le fait que nous utilisions des méthodes statiques signifie qu'il y a une raison valable d'avoir un modèle d'interface qui inclut des méthodes statiques - je ne peux pas parler pour l'un d'entre vous, mais j'utilise régulièrement des méthodes statiques.

La réponse la plus probable est qu'il n'y avait pas de besoin perçu, au moment où le langage a été défini, de méthodes statiques dans les interfaces. Java a beaucoup évolué au fil des ans et ce point a apparemment suscité un certain intérêt. Le fait qu'il ait été examiné pour Java 7 indique qu'il a atteint un niveau d'intérêt qui pourrait entraîner un changement de langage. Pour ma part, je serai heureux lorsque je ne devrai plus instancier un objet pour pouvoir appeler ma méthode getter non statique pour accéder à une variable statique dans une instance de sous-classe...

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X