Question

Le sujet en dit long : 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 les publics et les résumés sont autorisés".

Était-ce utile?

La solution

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 Espo mentionne :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 !

Autres conseils

La raison pour laquelle vous ne pouvez pas avoir de méthode statique dans une interface réside dans la manière dont Java résout les références statiques.Java ne prendra pas la peine de rechercher une instance d'une classe lorsqu'il tentera d'exécuter 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 VM 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.

Je vais répondre à votre question avec un exemple.Supposons que nous ayons une classe Math avec une méthode statique ajoutée.Vous appelleriez cette méthode comme ceci :

Math.add(2, 3);

Si Math était une interface plutôt qu’une classe, elle ne pourrait avoir aucune fonction définie.En tant que tel, dire quelque chose comme Math.add(2, 3) n'a aucun sens.

La raison réside dans le principe de conception, selon lequel Java n'autorise 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 C.x() ?Sera A.x() ou B.x() exécuté ?Chaque langage à 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 de 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 C.x() ?

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 depuis l'interface n'a pas de sens.

Désormais, 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
   }
}

Note: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.

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

Il semble que la méthode statique de l'interface puisse être prise en charge dans Java8, 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 accessible sous la forme de Interface.fn... au lieu de Class.fn..., vous pouvez alors vous débarrasser du problème ambigu.

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

Java 8 a 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);

}

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 abstraite 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 modifier 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.

Puisque les méthodes statiques ne peuvent pas être héritées.Donc inutile de le placer dans l’interface.Interface est essentiellement un contrat que tous ses abonnés doivent respecter.Placer une méthode statique dans l'interface obligera 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.

Avec Java8, 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 désormais déclarer des implémentations de méthodes « 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.

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

Imaginons 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, imaginons que nous ayons 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 $ sur 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 boucle sur les IPayable dans accountToPay, il n'y aurait aucun moyen de savoir s'il doit appeler le paiement sur BusinessAcount ou CustomerAccount.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top