Réponses:
Oui, vous pouvez créer à la fois une classe imbriquée ou une classe interne dans une interface Java (notez que contrairement à la croyance populaire, il n'y a pas de " classe interne statique ": cela n'a tout simplement aucun sens, il n'y a rien de "interne" et non " outter "quand une classe imbriquée est statique, donc elle ne peut pas être" statique interne ").
Quoi qu'il en soit, ce qui suit se compile bien:
public interface A {
class B {
}
}
Je l'ai vu utilisé pour mettre une sorte de "vérificateur de contrat" directement dans la définition de l'interface (enfin, dans la classe imbriquée dans l'interface, qui peut avoir des méthodes statiques, contrairement à l'interface elle-même, qui ne le peut pas). Ressemblant à ça si je me souviens bien.
public interface A {
static class B {
public static boolean verifyState( A a ) {
return (true if object implementing class A looks to be in a valid state)
}
}
}
Notez que je ne fais pas de commentaires sur l'utilité d'une telle chose, je réponds simplement à votre question: cela peut être fait et c'est un type d'utilisation que j'ai vu en faire.
Maintenant, je ne commenterai pas l'utilité d'une telle construction et d'après ce que j'ai vu: je l'ai vue, mais ce n'est pas une construction très courante.
200KLOC codebase ici où cela se produit exactement à zéro heure (mais alors nous avons beaucoup d'autres choses que nous considérons comme de mauvaises pratiques qui se produisent exactement à zéro heure aussi que d'autres personnes trouveraient parfaitement normales alors ...).
interface
s ne peut pas avoir de classes internes. Vous pouvez omettre le static
modificateur de interface
la classe imbriquée d'une classe, mais c'est quand même une classe imbriquée, pas une classe interne.
B
classe est une classe imbriquée statique et non une classe interne; les interfaces reçoivent un traitement spécial. Je n'ai pas trouvé de mention de cela en ligne, sauf dans la spécification elle-même: "Une classe membre d'une interface est implicitement statique et n'est donc jamais considérée comme une classe interne." docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.1.3
Oui, nous pouvons avoir des classes à l'intérieur des interfaces. Un exemple d'utilisation pourrait être
public interface Input
{
public static class KeyEvent {
public static final int KEY_DOWN = 0;
public static final int KEY_UP = 1;
public int type;
public int keyCode;
public char keyChar;
}
public static class TouchEvent {
public static final int TOUCH_DOWN = 0;
public static final int TOUCH_UP = 1;
public static final int TOUCH_DRAGGED = 2;
public int type;
public int x, y;
public int pointer;
}
public boolean isKeyPressed(int keyCode);
public boolean isTouchDown(int pointer);
public int getTouchX(int pointer);
public int getTouchY(int pointer);
public float getAccelX();
public float getAccelY();
public float getAccelZ();
public List<KeyEvent> getKeyEvents();
public List<TouchEvent> getTouchEvents();
}
Ici, le code a deux classes imbriquées qui sont destinées à encapsuler des informations sur les objets événement qui sont ensuite utilisés dans les définitions de méthode comme getKeyEvents (). Les avoir à l'intérieur de l'interface d'entrée améliore la cohésion.
Une utilisation valide, à mon humble avis, définit les objets qui sont reçus ou renvoyés par les méthodes d'interface englobantes. Typiquement des structures de stockage de données. De cette façon, si l'objet n'est utilisé que pour cette interface, vous avez les choses d'une manière plus cohérente.
Par exemple:
interface UserChecker {
Ticket validateUser(Credentials credentials);
class Credentials {
// user and password
}
class Ticket {
// some obscure implementation
}
}
Mais de toute façon ... ce n'est qu'une question de goût.
Citation de la spécification Java 7 :
Les interfaces peuvent contenir des déclarations de type de membre (§8.5).
Une déclaration de type de membre dans une interface est implicitement statique et publique. Il est permis de spécifier de manière redondante l'un ou les deux de ces modificateurs.
Il n'est PAS possible de déclarer des classes non statiques dans une interface Java, ce qui me semble logique.
Un cas d'utilisation intéressant est de fournir une sorte d'implémentation par défaut aux méthodes d'interface via une classe interne, comme décrit ici: https://stackoverflow.com/a/3442218/454667 (pour surmonter le problème de l'héritage de classe unique).
C'est certainement possible, et un cas où je l'ai trouvé utile est lorsqu'une interface doit lever des exceptions personnalisées. Vous gardez les exceptions avec leur interface associée, ce qui, je pense, est souvent plus soigné que de joncher votre arbre source avec des tas de fichiers d'exceptions triviaux.
interface MyInterface {
public static class MyInterfaceException extends Exception {
}
void doSomething() throws MyInterfaceException;
}
Oui, il est possible d'avoir des définitions de classe statiques dans une interface, mais peut-être que l'aspect le plus utile de cette fonctionnalité est l'utilisation de types enum (qui sont des types spéciaux de classes statiques). Par exemple, vous pouvez avoir quelque chose comme ceci:
public interface User {
public enum Role {
ADMIN("administrator"),
EDITOR("editor"),
VANILLA("regular user");
private String description;
private Role(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}
public String getName();
public void setName(String name);
public Role getRole();
public void setRole(Role role);
...
}
Ce que @Bachi mentionne est similaire aux traits de Scala et est en fait implémenté à l'aide d'une classe imbriquée dans une interface. Cela peut être simulé en Java. Voir aussi les traits java ou le modèle mixins?
Peut-être que lorsque vous voulez des constructions plus complexes comme des comportements d'implémentation différents, considérez:
public interface A {
public void foo();
public static class B implements A {
@Override
public void foo() {
System.out.println("B foo");
}
}
}
Ceci est votre interface et ce sera la personne implémentée:
public class C implements A {
@Override
public void foo() {
A.B b = new A.B();
b.foo();
}
public static void main(String[] strings) {
C c = new C();
c.foo();
}
}
Peut fournir des implémentations statiques, mais n'est-ce pas déroutant, je ne sais pas.
J'ai trouvé une utilisation pour ce type de construction.
Vous avez accès à toutes les constantes regroupées; nom de la classe agit comme un espace de noms dans ce cas.
J'en ai besoin maintenant. J'ai une interface où il serait pratique de renvoyer une classe unique à partir de plusieurs de ses méthodes. Cette classe n'a de sens qu'en tant que conteneur pour les réponses des méthodes de cette interface.
Par conséquent, il serait pratique d'avoir une définition de classe imbriquée statique, qui n'est associée qu'à cette interface, puisque cette interface devrait être le seul endroit où cette classe de conteneur de résultats est jamais créée.