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


Voici l'exemple:

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

Bien sûr, cela ne fonctionnera pas. Mais pourquoi pas?

Un des problèmes possibles serait, que se passe-t-il lorsque vous appelez:

IXMLizable.newInstanceFromXML(e);

Dans ce cas, je pense qu'il devrait simplement appeler une méthode vide (c'est-à-dire {}). Toutes les sous-classes seraient obligées d'implémenter la méthode statique, elles seraient donc toutes correctes lors de l'appel de la méthode statique. Alors pourquoi n'est-ce pas possible?

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

Existe-t-il une raison technologique particulière pour laquelle les méthodes statiques ne peuvent pas être écrasées? Autrement dit, pourquoi les concepteurs de Java ont-ils décidé de rendre les méthodes d'instance substituables, mais pas les méthodes statiques?

MODIFIER: Le problème avec ma conception est que j'essaie d'utiliser des interfaces pour appliquer une convention de codage.

Autrement dit, le but 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, ça marche bien).

  2. Si quelqu'un veut faire une nouvelle instance d'une classe qui implémente l'interface IXMLizable, ils sauront toujours qu'il y aura un newInstanceFromXML (élément e) du constructeur statique.

Y a-t-il un autre moyen d'assurer cela, autre que de simplement ajouter un commentaire dans l'interface?

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


417
2018-02-04 19:21


origine


Réponses:


Java 8 autorise les méthodes d'interface statique

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

Il y a vraiment deux questions ici:

  1. Pourquoi, dans le mauvais vieux temps, les interfaces ne pouvaient-elles pas contenir des méthodes statiques?
  2. Pourquoi les méthodes statiques ne peuvent-elles pas être remplacées?

Méthodes statiques dans les interfaces

Il n'y avait pas de raison technique forte pour laquelle les interfaces ne pouvaient pas avoir de méthodes statiques dans les versions précédentes. C'est résume bien par l'affiche d'une question en double. Les méthodes d'interface statique ont été initialement considérées comme un petit changement de langue, et puis il y avait une proposition officielle pour les ajouter dans Java 7, mais c'était 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 remplaçables avec une implémentation par défaut. Ils ne peuvent toujours pas avoir de champs d'instance. Ces fonctionnalités font partie du support de l'expression lambda, et vous pouvez en lire plus à leur sujet dans Partie H de la JSR 335.

Surcharger les méthodes statiques

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

Les méthodes statiques sont résolvables au moment de la compilation. La distribution dynamique a du sens pour les méthodes d'instance, où 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 invoquer une méthode statique nécessite une classe, et puisque cette classe est connue statiquement-dans la compilation, la répartition dynamique dans le temps est inutile.

Un peu de contexte sur le fonctionnement des méthodes d'instance est nécessaire pour comprendre ce qui se passe ici. Je suis sûr que la mise en œuvre est très différente, mais permettez-moi d’expliquer ma notion de répartition des méthodes, qui modélise avec précision le comportement observé.

Imaginons que chaque classe possède une table de hachage qui mappe les signatures de méthode (nom et types de paramètre) à 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 sa classe et recherche la signature demandée dans la table de la classe. Si un corps de méthode est trouvé, il est appelé. Sinon, la classe parente de la classe est obtenue et la recherche est répétée ici. Cela se poursuit jusqu'à ce que la méthode soit trouvée ou qu'il n'y ait plus de classes parentes, ce qui se traduit par 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 - c'est un "override".

Supposons maintenant que nous ignorions l'instance de l'objet et que nous commencions par une sous-classe. La résolution pourrait se dérouler comme ci-dessus, vous donnant une sorte de méthode statique "overridable". La résolution peut cependant se produire à la compilation, car le compilateur commence à partir d'une classe connue, plutôt que d'attendre l'exécution pour interroger un objet d'un type non spécifié pour sa classe. Il ne sert à rien de "remplacer" une méthode statique car on peut toujours spécifier la classe qui contient la version souhaitée.


Constructeur "interfaces"

Voici un peu plus de matériel pour aborder le récent montage de la question.

Il semble que vous souhaitiez imposer une méthode de type constructeur pour chaque implémentation de IXMLizable. Oubliez d'essayer d'appliquer cela avec une interface pendant une minute, et prétendez 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 de béton Foo Lors de la "construction" du nouvel objet, le compilateur peut vérifier qu'il possède bien la méthode d'usine requise. Et si ce n'est pas le cas, alors quoi? Si je peux mettre en œuvre un IXMLizable qui manque le "constructeur", et je crée une instance et la passe à votre code, il est un IXMLizable avec toutes les interfaces nécessaires.

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


445
2018-02-04 19:56



Cela a déjà été demandé et répondu, ici

Pour dupliquer ma réponse:

Il n'y a jamais de sens à déclarer une méthode statique dans une interface. Ils ne peuvent pas être exécutés par l'appel normal MyInterface.staticMethod (). Si vous les appelez en spécifiant la classe d'implémentation MyImplementor.staticMethod (), vous devez connaître la classe réelle, donc peu importe que l'interface la contienne ou non.

Plus important encore, les méthodes statiques ne sont jamais remplacées, et si vous essayez de 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. Puisque c'est une interface, c'est impossible.

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

Alors que vous pouvez dire que cela revient à «parce que Java le fait de cette façon», en réalité, la décision est une conséquence logique d'autres décisions de conception, également faites pour une très bonne raison.


42
2018-02-04 19:50



Normalement, cela est fait en utilisant un motif d'usine

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

public interface IXMLizable {
  public Element toXMLElement();
}

34
2018-02-13 21:37



Avec l'avènement de Java 8 il est possible maintenant d'écrire défaut et statique méthodes en interface. docs.oracle/staticMethod

Par exemple:

public interface Arithmetic {

    public int add(int a, int b);

    public static int multiply(int a, int b) {
        return a * b;
    }
}
public class ArithmaticImplementation implements Arithmetic {

    @Override
    public int add(int a, int b) {
        return a + b;
    }

    public static void main(String[] args) {
        int result = Arithmetic.multiply(2, 3);
        System.out.println(result);
    }
}

Résultat : 6

POINTE : L'appel d'une méthode d'interface statique ne nécessite aucune implémentation par une classe. Cela se produit certainement parce que les mêmes règles pour les méthodes statiques dans les superclasses s'appliquent aux méthodes statiques sur les interfaces.


29
2017-11-26 17:13



Parce que les méthodes statiques ne peuvent pas être remplacées dans les sous-classes, elles ne peuvent donc pas être abstraites. Et toutes les méthodes dans une interface sont, de facto, abstrait.


19
2018-02-04 19:22



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

En fait, vous pouvez en Java 8.

Selon Java doc:

Une méthode statique est une méthode associée à la classe dans laquelle   c'est défini plutôt qu'avec n'importe quel objet. Chaque instance de la classe   partage ses méthodes statiques

Dans Java 8, une interface peut avoir méthodes par défaut et méthodes statiques. Cela nous permet d'organiser plus facilement les méthodes d'assistance dans nos bibliothèques. Nous pouvons garder des méthodes statiques spécifiques à une interface dans la même interface plutôt que dans une classe séparée.

Exemple de méthode par défaut:

list.sort(ordering);

au lieu de

Collections.sort(list, ordering);

Exemple de méthode statique (de doc lui-même):

public interface TimeClient {
    // ...
    static public 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 public ZonedDateTime getZonedDateTime(String zoneString) {
        return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
    }    
}

9
2017-07-01 13:33



Premièrement, toutes les décisions linguistiques sont des décisions prises par les créateurs de langues. Il n'y a rien dans le monde du génie logiciel ou de la définition de langage ou de l'écriture de compilateur / interprète qui dit qu'une méthode statique ne peut pas faire partie d'une interface. J'ai créé deux langages et des compilateurs écrits pour eux - tout est juste assis et définissant 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 à l'exécution.

Deuxièmement, nous utilisons des méthodes statiques à tous les moyens, il y a une raison valable pour avoir un modèle d'interface qui inclut des méthodes statiques - je ne peux parler pour aucun d'entre vous, mais j'utilise des méthodes statiques sur une base régulière.

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


6
2017-07-05 22:54



Les interfaces concernent le polymorphisme qui est intrinsèquement lié aux instances d'objet, et non aux classes. Par conséquent, le statique n’a pas de sens dans le contexte d’une interface.


5
2018-02-04 19:28