Pourquoi tous les champs d'une interface sont-ils implicitement statiques et définitifs?

100

J'essaie juste de comprendre pourquoi tous les champs définis dans une interface sont implicitement staticet final. L'idée de garder des champs a du staticsens pour moi car vous ne pouvez pas avoir d'objets d'une interface mais pourquoi ils le sont final(implicitement)?

Tout le monde sait pourquoi les concepteurs Java ont choisi de créer les champs dans une interface staticet final?

peakit
la source
Pour une note pour moi-même: c'est statique car les champs d'interface ne feront pas partie de l'objet qui l'implémente.
pleut le

Réponses:

126

Une interface ne peut pas avoir de comportement ou d'état car elle est destinée à spécifier uniquement un contrat d'interaction, pas de détails d'implémentation. 'Aucun comportement' est appliqué en n'autorisant pas les corps de méthode / constructeur ou les blocs d'initialisation statiques / d'instance. «Aucun état» est appliqué en autorisant uniquement les champs finaux statiques. Par conséquent, la classe peut avoir un état (état statique), mais l'état de l'instance n'est pas déduit par l'interface.

BTW: Une constante en Java est définie par un champ final statique (et par convention le nom utilise UPPER_CASE_AND_UNDERSCORES).

Adriaan Koster
la source
54
Il n'est pas nécessairement vrai que les champs finaux sont des constantes; ce n'est garanti que pour les types primitifs. En général, le mot-clé final signifie simplement que l'emplacement mémoire ne changera pas.
Pops
8
Je n'ai pas dit que les champs finaux sont des constantes, juste que les constantes sont des champs finaux. Notez qu'il est permis de mettre un champ final statique non primitif dans une interface. Même si le contenu de ce champ peut changer, la référence à celui-ci est constante.
Adriaan Koster
1
@AdriaanKoster Vous avez dit exactement que le champ final est constant: aucun état n'est appliqué en n'autorisant que les constantes. - cette phrase implique que tous les champs finaux sont constants. Vous pourriez essayer de discuter davantage des mots que vous avez utilisés, mais votre déclaration est évidemment trompeuse.
Tomáš Zato - Réintégrer Monica
2
Cela doit être mon intellect décroissant, mais après six ans à regarder cette réponse, qui se trouve être ma meilleure réponse, je ne comprends toujours pas les remarques. Veuillez suggérer un libellé différent car je ne vois rien de mal.
Adriaan Koster
Les concepteurs de Java avaient peut-être l'intention de rendre une interface sans état, mais ils ont échoué car un champ d'instance peut être une classe modifiable. Au lieu d'admettre qu'ils ont échoué, ils choisissent de forcer les champs d'instance à static final, ce qui est aussi proche de réel (réel étant C / C ++) constque vous pouvez obtenir en java. Malheureusement, cela est implicite et peut prêter à confusion pour le non-expert. (Je viens de réaliser qu'ils le sont staticparce que j'ai observé un comportement involontaire. J'ai appris qu'ils finalne sont que de cette réponse.)
not-a-user
27

Raison d'être final

Toutes les implémentations peuvent changer la valeur des champs si elles ne sont pas définies comme définitives. Ensuite, ils feraient partie de la mise en œuvre. Une interface est une spécification pure sans aucune implémentation.

Raison d'être static

S'ils sont statiques, ils appartiennent à l'interface, et non à l'objet, ni au type d'exécution de l'objet.

Gurpreet Singh Sidhuu
la source
18

Il y a quelques points passés sous silence ici:

Ce n'est pas parce que les champs d'une interface sont implicitement statiques finaux qu'ils doivent être des constantes à la compilation, ou même immuables. Vous pouvez définir par exemple

interface I {
  String TOKEN = SomeOtherClass.heavyComputation();
  JButton BAD_IDEA = new JButton("hello");
}

(Méfiez-vous que faire cela dans une définition d'annotation peut confondre javac , lié au fait que ce qui précède se compile réellement en un initialiseur statique.)

De plus, la raison de cette restriction est plus stylistique que technique, et beaucoup de gens aimeraient qu'elle soit détendue .

Jesse Glick
la source
9

Les champs doivent être statiques car ils ne peuvent pas être abstraits (comme le peuvent les méthodes). Parce qu'ils ne peuvent pas être abstraits, les implémenteurs ne seront pas en mesure de fournir logiquement les différentes implémentations des champs.

Les champs doivent être définitifs, je pense, car les champs peuvent être accédés par de nombreux implémenteurs différents, ce qui leur permet d'être modifiables peut être problématique (comme la synchronisation). Aussi pour éviter qu'il soit réimplémenté (caché).

Juste ma pensée.

NawaMan
la source
NawMan, votre explication sur "Les champs doivent être statiques ..." n'a pas beaucoup de sens. Mais vous aviez tout à fait raison sur le "Les champs doivent être définitifs ..."
peakit
1
Je ne pense pas qu'il ait raison sur la raison pour laquelle les champs doivent être définitifs. Permettre à différents implémenteurs de modifier un champ n'est pas problématique, sinon l'héritage serait problématique. Les champs doivent être définitifs, comme l'a dit Adriaan, car une interface est et doit être sans état. Une interface avec un état devrait être une classe abstraite.
Axelle Ziegler
Si vous avez un public staticchamp qui ne l'est pas final, findbugs se plaindra (à juste titre!).
Tom Hawtin - tackline
2

Je considère que l'exigence que les champs soient définitifs est indûment restrictive et constitue une erreur des concepteurs du langage Java. Il y a des moments, par exemple la gestion d'arborescence, où vous devez définir des constantes dans l'implémentation qui sont nécessaires pour effectuer des opérations sur un objet de type interface. La sélection d'un chemin de code sur la classe d'implémentation est un kludge. La solution de contournement que j'utilise est de définir une fonction d'interface et de l'implémenter en renvoyant un littéral:

public interface iMine {
    String __ImplementationConstant();
    ...
}

public class AClass implements iMine {
    public String __ImplementationConstant(){
        return "AClass value for the Implementation Constant";
    }
    ...
}

public class BClass implements iMine {
    public String __ImplementationConstant(){
        return "BClass value for the Implementation Constant";
    }
    ...
}

Cependant, il serait plus simple, plus clair et moins sujet à une implémentation aberrante d'utiliser cette syntaxe:

public interface iMine {
    String __ImplementationConstant;
    ...
}

public class AClass implements iMine {
    public static String __ImplementationConstant =
        "AClass value for the Implementation Constant";
    ...
}

public class BClass implements iMine {
    public static String __ImplementationConstant =
        "BClass value for the Implementation Constant";
    ...
}
Carl Klapper
la source
Vous semblez vous plaindre davantage du fait que les champs sont statiques plutôt que définitifs.
Daniel Yankowsky
0

Spécification, contrats ... L'instruction machine pour l'accès au champ utilise l'adresse de l'objet plus le décalage du champ. Comme les classes peuvent implémenter de nombreuses interfaces, il n'y a aucun moyen de faire en sorte que le champ d'interface non final ait le même décalage dans toutes les classes qui étendent cette interface. Par conséquent, un mécanisme différent pour l'accès au champ doit être implémenté: deux accès mémoire (obtenir le décalage du champ, obtenir la valeur du champ) au lieu d'un plus le type de table de champ virtuel (analogue de la table de méthode virtuelle). Je suppose qu'ils ne voulaient tout simplement pas compliquer jvm pour des fonctionnalités qui peuvent être facilement simulées via des éléments existants (méthodes).

Dans scala, nous pouvons avoir des champs dans les interfaces, bien qu'ils soient implémentés en interne comme je l'ai expliqué ci-dessus (en tant que méthodes).

Yaroslav
la source
-1

static:

Tout ce qui est staticen Java (variable ou méthode) peut être appelé en tant que Classname.variablenameou Classname.methodnameou directement. Il n'est pas obligatoire de l'invoquer uniquement en utilisant le nom de l'objet.

Dans l'interface, les objets ne peuvent pas être déclarés et staticpermettent d'appeler des variables uniquement via le nom de classe sans avoir besoin du nom d'objet.

final:

Cela aide à maintenir une valeur constante pour une variable car elle ne peut pas être remplacée dans ses sous-classes.

Sabika
la source