Classe interne dans l'interface


97

Est-il possible de créer une classe interne dans une interface?
Si c'est possible, pourquoi voudrions-nous créer une classe interne comme celle-là puisque nous n'allons pas créer d'objets d'interface?

Ces classes internes aident-elles dans un processus de développement?

Réponses:


51

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 ...).


Pouvez-vous ajouter quelques exemples d'utilisation? J'ai testé quelque chose de similaire il y a quelque temps et je n'ai pas compris ce que je peux gagner en utilisant cette construction.
Roman

@Roman: eh bien je me souviens que j'ai rencontré ça sur un projet (un projet relativement propre ajouterais-je mais ce n'était pas le mien) mais je ne sais pas si c'est vraiment propre ou pas. J'ai ajouté un petit exemple qui ressemble à ce que j'ai vu mais encore une fois: ce n'était pas mon code et je n'utilise pas cette construction donc je ne suis pas le plus qualifié pour trouver des exemples valides :) IIRC la classe à l'intérieur était toujours nommée, par exemple StateChecker et les appels ressembleraient toujours à: A.StateChecker.check (a) ou quelque chose comme ça.
SyntaxeT3rr0r

8
Si vous dites qu '"il n'y a pas de" classe interne statique "", votre réponse que "vous pouvez créer à la fois une classe imbriquée ou une classe interne dans une interface Java" est fondamentalement erronée. En utilisant votre définition restreinte, interfaces ne peut pas avoir de classes internes. Vous pouvez omettre le staticmodificateur de interfacela classe imbriquée d'une classe, mais c'est quand même une classe imbriquée, pas une classe interne.
Holger

6
Cette réponse est fausse. Les interfaces peuvent avoir des classes imbriquées statiques mais pas des classes internes.
Paul Boddington

1
@PaulBoddington Vous avez raison. Même en supprimant «statique», la Bclasse 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
Max Barraclough

109

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.


3
@Levit Vous vous demandez simplement à quoi ressemblera la classe implémentée?
surexchange le

1
J'adorerais voir une mise en œuvre en action pour l'utilisation ci-dessus. Je vous remercie.
Prakash K

45

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.


35

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.


Je vous remercie. C'est probablement la réponse la plus concise de toutes.
Joseph

1
C'est la réponse que je cherchais .. mais l'OP pose plusieurs questions .. de toute façon avoir mon updoot.
Charlie Wallace

11

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).


Et c'est exactement pourquoi les classes de membres privés auraient du sens.
Vincent

7

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;
}

7

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);
    ...
}


1

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.


0

J'ai trouvé une utilisation pour ce type de construction.

  1. Vous pouvez utiliser cette construction pour définir et regrouper toutes les constantes finales statiques.
  2. Depuis, c'est une interface que vous pouvez implémenter sur une classe.

Vous avez accès à toutes les constantes regroupées; nom de la classe agit comme un espace de noms dans ce cas.


0

Vous pouvez également créer des classes statiques "Helper" pour des fonctionnalités communes aux objets qui implémentent cette interface:

public interface A {
    static class Helper {
        public static void commonlyUsedMethod( A a ) {
           ...
        }
    }
}

0

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.


0

Par exemple, des traits (smth comme une interface avec des méthodes implémentées) dans Groovy. Ils sont compilés dans une interface qui contient une classe interne où toutes les méthodes sont implémentées.

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.