Pourquoi ne puis-je pas déclarer de méthodes statiques dans une interface?


150

Le sujet en dit le plus - quelle est la raison pour laquelle les méthodes statiques ne peuvent pas être déclarées dans une interface?

public interface ITest {
    public static String test();
}

Le code ci-dessus me donne l'erreur suivante (dans Eclipse, au moins): "Modificateur illégal pour la méthode d'interface ITest.test (); seuls public & abstract sont autorisés".


2
Veuillez refuser la réponse d'Espo, car elle est imparfaite. Une interface a un fichier de classe qui pourrait contenir l'implémentation d'une méthode statique (si le concepteur Java le permet), il n'y a donc aucun problème pour résoudre l'implémentation de la méthode statique. Cela fonctionne exactement comme avec les autres classes statiques.
Mnementh le

Je suis plutôt d'accord avec la réponse donnée par "erickson" stackoverflow.com/questions/512877/…
Maverick

9
Cela sera disponible dans Java 8 btw.
m0skit0

1
@Vadorequest GIYF mais de toute façon, vérifiez ici
m0skit0

2
Liens de la documentation officielle: tutoriel Java SE et spécification du langage Java 9.2
LoganMzz

Réponses:


85

Il y a quelques problèmes en jeu ici. Le premier est le problème de la déclaration d'une méthode statique sans la définir. C'est la différence entre

public interface Foo {
  public static int bar();
}

et

public interface Foo {
  public static int bar() {
    ...
  }
}

La première est impossible pour les raisons mentionnées par Espo : vous ne savez pas quelle classe d'implémentation est la bonne définition.

Java pourrait permettre ce dernier; et en fait, à partir de Java 8, c'est le cas!


2
Oui - c'est idealogique pas technique. La raison pour laquelle je voudrais que ce soit. qu'on peut avoir une méthode statique "d'implémentation" dans une interface qui ne fait référence qu'à d'autres méthodes "d'interface" dans l'interface qui peuvent être facilement réutilisées en implémentant des classes. Mais on peut déclarer une classe statique dans une interface afin que de telles choses y résident comme MyInterface.Impl.doIt (MyInterface i, Object [] args) {...}
peterk

9
Depuis Java 8, vous pouvez définir des staticméthodes dans un fichier interface. Les méthodes doivent être public.
Olivier Grégoire

4
@ OlivierGrégoire ... et ils ne sont pas hérités, ce qui est essentiel.
William F. Jameson

1
Bonne réponse, bien que "à peu près équivalent" ROFLMAO xD J'aurais plutôt mis ça comme "un peu ressemble".
Timo

44

La raison pour laquelle vous ne pouvez pas avoir de méthode statique dans une interface réside dans la façon dont Java résout les références statiques. Java ne prendra pas la peine de rechercher une instance d'une classe lors d'une tentative d'exécution d'une méthode statique. En effet, les méthodes statiques ne dépendent pas de l'instance et peuvent donc être exécutées directement à partir du fichier de classe. Étant donné que toutes les méthodes d'une interface sont abstraites, la machine virtuelle devrait rechercher une implémentation particulière de l'interface afin de trouver le code derrière la méthode statique afin qu'elle puisse être exécutée. Cela contredit alors le fonctionnement de la résolution de méthode statique et introduirait une incohérence dans le langage.


3
Cette explication n'explique pas le problème. Chaque interface a son propre fichier de classe, il peut contenir la méthode statique. Aucune recherche d'une implémentation particulière ne serait donc nécessaire.
Mnementh le

Tous les types d'interface en Java ne se trouvent pas dans leur propre fichier, et ne devraient pas non plus l'être selon JLS. De plus, JLS ne stipule pas que les classes doivent toujours être stockées dans un système de fichiers, bien au contraire.
Vlad Gudim le

4
@Totophil: Les interfaces ne doivent pas être dans un seul fichier java, mais il aura un propre fichier de classe après la compilation. C'est ce que j'ai écrit.
Mnementh le

18

Je répondrai à votre question par un exemple. Supposons que nous ayons une classe Math avec une méthode statique add. Vous appelleriez cette méthode comme ceci:

Math.add(2, 3);

Si Math était une interface au lieu d'une classe, il ne pourrait pas avoir de fonctions définies. En tant que tel, dire quelque chose comme Math.add (2, 3) n'a aucun sens.


11

La raison réside dans le principe de conception, que java ne permet pas l'héritage multiple. Le problème de l'héritage multiple peut être illustré par l'exemple suivant:

public class A {
   public method x() {...}
}
public class B {
   public method x() {...}
}
public class C extends A, B { ... }

Maintenant, que se passe-t-il si vous appelez Cx ()? Est-ce que Ax () ou Bx () sera exécuté? Chaque langue à héritage multiple doit résoudre ce problème.

Les interfaces permettent en Java une sorte d'héritage multiple restreint. Pour éviter le problème ci-dessus, ils ne sont pas autorisés à avoir des méthodes. Si nous regardons le même problème avec les interfaces et les méthodes statiques:

public interface A {
   public static method x() {...}
}
public interface B {
   public static method x() {...}
}
public class C implements A, B { ... }

Même problème ici, que se passe-t-il si vous appelez Cx ()?


Une raison pour le vote défavorable? Un commentaire explicatif serait bien.
Mnementh

Je ne suis pas le downvoter, mais n'est-ce pas également valable pour les méthodes non statiques?
nawfal

OK, voici deux possibilités différentes. Une méthode peut être implémentée ou seulement déclarée. J'ai compris que la méthode statique doit être mise en œuvre. En ce sens, je rencontre le problème présenté dans ma réponse. Si vous ne le faites pas, vous rencontrez le problème décrit par Espo - et que je n'ai pas compris car j'ai supposé que la méthode statique serait implémentée. Vous ne pouvez pas non plus déclarer une méthode abstraite statique pour cette raison, essayez-la, le compilateur se plaindra.
Mnementh

Ok, oubliez la partie implémentation. la question est de savoir pourquoi ne pouvons-nous pas déclarer. oui le compilateur se plaindra et pourquoi est-ce la question. auquel je ne pense pas que vous ayez répondu.
nawfal

1
Comment la situation il être pire que d' avoir l' interface Acontiennent int x(int z);et de l' interface Bcontiennent string x(int x);? Quelle est la signification de x(3)dans l'interface C?
supercat

7

Les méthodes statiques ne sont pas des méthodes d'instance. Il n'y a pas de contexte d'instance, donc l'implémenter à partir de l'interface n'a pas de sens.


5

Maintenant, Java8 nous permet de définir même des méthodes statiques dans l'interface.

interface X {
    static void foo() {
       System.out.println("foo");
    }
}

class Y implements X {
    //...
}

public class Z {
   public static void main(String[] args) {
      X.foo();
      // Y.foo(); // won't compile because foo() is a Static Method of X and not Y
   }
}

Remarque: les méthodes dans Interface sont toujours publiques abstraites par défaut si nous n'utilisons pas explicitement les mots-clés default / static pour en faire des méthodes par défaut et des méthodes statiques resp.


4

Il y a une réponse très agréable et concise à votre question ici . (Cela m'a frappé comme une façon si simple de l'expliquer que je veux le lier à partir d'ici.)


Ce n'est pas une réponse à la question, au mieux cela devrait être un commentaire.
CubeJockey

3

Il semble que la méthode statique de l'interface puisse être prise en charge dans Java 8 , eh bien, ma solution consiste simplement à les définir dans la classe interne.

interface Foo {
    // ...
    class fn {
        public static void func1(...) {
            // ...
        }
    }
}

La même technique peut également être utilisée dans les annotations:

public @interface Foo {
    String value();

    class fn {
        public static String getValue(Object obj) {
            Foo foo = obj.getClass().getAnnotation(Foo.class);
            return foo == null ? null : foo.value();
        }
    }
}

La classe interne doit toujours être accédée sous la forme Interface.fn...au lieu de Class.fn..., alors, vous pouvez vous débarrasser du problème ambigu.


2

Une interface est utilisée pour le polymorphisme, qui s'applique aux objets, pas aux types. Par conséquent (comme déjà noté) cela n'a aucun sens d'avoir un membre d'interface statique.


Dans certains contextes de réflexion, cela semble presque avoir du sens
Cruncher

1

Java 8 Avait changé le monde, vous pouvez avoir des méthodes statiques dans l'interface, mais cela vous oblige à fournir une implémentation pour cela.

public interface StaticMethodInterface {
public static int testStaticMethod() {
    return 0;
}

/**
 * Illegal combination of modifiers for the interface method
 * testStaticMethod; only one of abstract, default, or static permitted
 * 
 * @param i
 * @return
 */
// public static abstract int testStaticMethod(float i);

default int testNonStaticMethod() {
    return 1;
}

/**
 * Without implementation.
 * 
 * @param i
 * @return
 */
int testNonStaticMethod(float i);

}


0

Combinaison illégale de modificateurs: statique et abstrait

Si un membre d'une classe est déclaré statique, il peut être utilisé avec son nom de classe qui est confiné à cette classe, sans créer d'objet.

Si un membre d'une classe est déclaré comme abstrait, vous devez déclarer la classe comme abstrait et vous devez fournir l'implémentation du membre abstrait dans sa classe héritée (sous-classe).

Vous devez fournir une implémentation au membre abstrait d'une classe dans une sous-classe où vous allez changer le comportement de la méthode statique, également déclarée comme abstraite qui est confinée à la classe de base, ce qui n'est pas correct


Comment cela répond-il à la question? L'OP a posé des questions sur l'interface pendant que vous écriviez sur la classe.
Lucky

0

Puisque les méthodes statiques ne peuvent pas être héritées. Donc inutile de le placer dans l'interface. L'interface est essentiellement un contrat que tous ses abonnés doivent suivre. Placer une méthode statique dans l'interface forcera les abonnés à l'implémenter. ce qui devient désormais contradictoire avec le fait que les méthodes statiques ne peuvent pas être héritées.


Les méthodes statiques sont toujours héritées mais elles ne peuvent pas être remplacées.
Akki

0

Avec Java 8 , les interfaces peuvent désormais avoir des méthodes statiques.

Par exemple, Comparator a une méthode statique naturalOrder ().

L'exigence selon laquelle les interfaces ne peuvent pas avoir d'implémentations a également été assouplie. Les interfaces peuvent maintenant déclarer des implémentations de méthode "par défaut", qui sont comme des implémentations normales à une exception près: si vous héritez à la fois d'une implémentation par défaut d'une interface et d'une implémentation normale d'une superclasse, l'implémentation de la superclasse sera toujours prioritaire.


OMG! Nous avons un programmeur sérieux (et moi, commentateur) répondant (et moi, commentant) une question vieille de 10 ans.
Mohamed Anees A

Je n'ai pas remarqué la date :)
Ishara

Haha! Aucun problème!
Mohamed Anees A

-2

Peut-être qu'un exemple de code pourrait vous aider, je vais utiliser C #, mais vous devriez pouvoir suivre.

Supposons que nous ayons une interface appelée IPayable

public interface IPayable
{
    public Pay(double amount);
}

Maintenant, nous avons deux classes concrètes qui implémentent cette interface:

public class BusinessAccount : IPayable
{
    public void Pay(double amount)
    {
        //Logic
    }
}

public class CustomerAccount : IPayable
{
    public void Pay(double amount)
    {
        //Logic
    }
}

Maintenant, faisons comme si nous avons une collection de différents comptes, pour ce faire nous utiliserons une liste générique du type IPayable

List<IPayable> accountsToPay = new List<IPayable>();
accountsToPay.add(new CustomerAccount());
accountsToPay.add(new BusinessAccount());

Maintenant, nous voulons payer 50,00 $ à tous ces comptes:

foreach (IPayable account in accountsToPay)
{
    account.Pay(50.00);
}

Alors maintenant, vous voyez à quel point les interfaces sont incroyablement utiles.

Ils sont utilisés uniquement sur les objets instanciés. Pas sur les classes statiques.

Si vous aviez rendu le paiement statique, lors de la lecture en boucle de l'IPayable dans accountsToPay, il n'y aurait aucun moyen de savoir s'il devrait appeler le paiement sur BusinessAcount ou CustomerAccount.


Ce n'est pas parce que les méthodes statiques n'ont aucun sens dans cet exemple qu'elles n'ont aucun sens dans N'IMPORTE QUEL exemple. Dans votre exemple, si l'interface IPayable avait une méthode statique "IncrementPayables" qui gardait une trace du nombre de dettes ajoutées, ce serait un cas d'utilisation réel. Bien sûr, on pourrait toujours utiliser une classe abstraite, mais ce n'est pas ce que vous avez abordé. Votre exemple en lui-même ne sape pas les méthodes statiques dans les interfaces.
Cruncher
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.