Classe interna all'interno dell'interfaccia


97

È possibile creare una classe interna all'interno di un'interfaccia?
Se è possibile, perché dovremmo creare una classe interna come quella poiché non creeremo alcun oggetto dell'interfaccia?

Queste classi interne aiutano in qualsiasi processo di sviluppo?

Risposte:


51

Sì, puoi creare sia una classe nidificata che una classe interna all'interno di un'interfaccia Java (nota che contrariamente alla credenza popolare non esiste una " classe interna statica ": questo semplicemente non ha senso, non c'è niente di "interno" e no " outter "quando una classe nidificata è statica, quindi non può essere" statica interna ").

Ad ogni modo, il seguente viene compilato correttamente:

public interface A {
    class B {
    }
}

L'ho visto usato per mettere una sorta di "controllo del contratto" direttamente nella definizione dell'interfaccia (beh, nella classe annidata nell'interfaccia, che può avere metodi statici, contrariamente all'interfaccia stessa, che non può). Assomiglia a questo se ricordo bene.

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

Nota che non sto commentando l'utilità di una cosa del genere, sto semplicemente rispondendo alla tua domanda: si può fare e questo è un tipo di utilizzo che ne ho visto fare.

Ora non voglio commentare l'utilità di un tale costrutto e da quello che ho visto: l'ho visto, ma non è un costrutto molto comune.

Codebase 200KLOC qui dove questo accade esattamente a tempo zero (ma poi abbiamo molte altre cose che consideriamo cattive pratiche che accadono esattamente a tempo zero che altre persone troverebbero perfettamente normali quindi ...).


Puoi aggiungere alcuni esempi di utilizzo? Ho provato qualcosa di simile qualche tempo fa e non ho capito cosa posso ottenere dall'uso di questa costruzione.
Roman

@Roman: beh, ricordo di averlo riscontrato su qualche progetto (un progetto relativamente pulito aggiungerei ma non erano miei) ma non so se sia veramente pulito o no. Ho aggiunto un piccolo esempio che assomiglia a quello che ho visto ma ancora una volta: questo non era il mio codice e non sto usando quel costrutto quindi non sono il più qualificato per fornire esempi validi :) IIRC la classe all'interno era sempre denominata, ad esempio StateChecker e le chiamate sarebbero sempre state: A.StateChecker.check (a) o qualcosa del genere.
SyntaxT3rr0r

8
Se dici che "non esiste una" classe interna statica "", la tua risposta che " puoi creare sia una classe nidificata che una classe interna all'interno di un'interfaccia Java" è fondamentalmente sbagliata. Usando la tua definizione ristretta, interfaces non può avere classi interne. Puoi omettere il staticmodificatore di una interfaceclasse nidificata, ma è comunque una classe nidificata, non una classe interna.
Holger

6
Questa risposta è sbagliata. Le interfacce possono avere classi annidate statiche ma non classi interne.
Paul Boddington

1
@PaulBoddington Hai ragione. Anche rimuovendo "statica", la Bclasse è una classe annidata statica e non una classe interna; le interfacce ricevono un trattamento speciale. Non sono riuscito a trovare menzione di questo in linea, tranne che nella specifica stessa: "Una classe membro di un'interfaccia è implicitamente statica, quindi non viene mai considerata una classe interna". docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.1.3
Max Barraclough

109

Sì, possiamo avere classi all'interno delle interfacce. Un esempio di utilizzo potrebbe essere

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

Qui il codice ha due classi annidate che servono a incapsulare le informazioni sugli oggetti evento che vengono successivamente utilizzati nelle definizioni dei metodi come getKeyEvents (). Averli all'interno dell'interfaccia di input migliora la coesione.


3
@ Levit Mi chiedo solo come sarà la classe implementata?
scambio eccessivo

1
Mi piacerebbe vedere un'implementazione in azione per l'utilizzo di cui sopra. Grazie.
Prakash K

45

Un uso valido, IMHO, è la definizione di oggetti ricevuti o restituiti dai metodi dell'interfaccia che li racchiude. Tipicamente strutture di contenimento dei dati. In questo modo, se l'oggetto viene utilizzato solo per quell'interfaccia, hai le cose in un modo più coeso.

Per esempio:

interface UserChecker {
   Ticket validateUser(Credentials credentials);

   class Credentials {
      // user and password
   }

   class Ticket {
      // some obscure implementation
   }
}

Ma comunque ... è solo questione di gusti.


35

Citazione dalla specifica Java 7 :

Le interfacce possono contenere dichiarazioni del tipo di membro (§8.5).

Una dichiarazione del tipo di membro in un'interfaccia è implicitamente statica e pubblica. È consentito specificare in modo ridondante uno o entrambi questi modificatori.

NON è possibile dichiarare classi non statiche all'interno di un'interfaccia Java, il che ha senso per me.


Grazie. Questa è probabilmente la risposta più concisa di tutte.
Joseph,

1
Questa è la risposta che stavo cercando .. ma l'OP fa diverse domande .. comunque ho il mio updoot.
Charlie Wallace

11

Un caso d'uso interessante è fornire una sorta di implementazione predefinita ai metodi di interfaccia tramite una classe interna come descritto qui: https://stackoverflow.com/a/3442218/454667 (per superare il problema dell'ereditarietà di una singola classe).


E questo è esattamente il motivo per cui le classi private dei membri avrebbero senso.
Vincent

7

Certamente è possibile, e un caso in cui l'ho trovato utile è quando un'interfaccia deve generare eccezioni personalizzate. Tieni le eccezioni con la loro interfaccia associata, che penso sia spesso più ordinata che sporcare il tuo albero dei sorgenti con un mucchio di banali file di eccezione.

interface MyInterface {

   public static class MyInterfaceException extends Exception {
   }

   void doSomething() throws MyInterfaceException;
}

7

Sì, è possibile avere definizioni di classi statiche all'interno di un'interfaccia, ma forse l'aspetto più utile di questa funzionalità è quando si utilizzano i tipi enum (che sono tipi speciali di classi statiche). Ad esempio puoi avere qualcosa del genere:

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

Ciò che @Bachi menziona è simile ai tratti in Scala e sono effettivamente implementati utilizzando una classe annidata all'interno di un'interfaccia. Questo può essere simulato in Java. Vedi anche tratti java o pattern mixin?


1

Forse quando desideri costruzioni più complesse come alcuni comportamenti di implementazione diversi, considera:

public interface A {
    public void foo();

    public static class B implements A {
        @Override
        public void foo() {
            System.out.println("B foo");
        }
    }
}

Questa è la tua interfaccia e questa sarà l'implementazione:

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

Può fornire alcune implementazioni statiche, ma non sarà fonte di confusione, non lo so.


0

Ho trovato un utilizzo per questo tipo di costrutto.

  1. È possibile utilizzare questo costrutto per definire e raggruppare tutte le costanti finali statiche.
  2. Poiché si tratta di un'interfaccia, puoi implementarla su una classe.

Hai accesso a tutte le costanti raggruppate; in questo caso il nome della classe funge da spazio dei nomi.


0

Puoi anche creare classi statiche "Helper" per funzionalità comuni per gli oggetti che implementano questa interfaccia:

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

0

Ne ho bisogno adesso. Ho un'interfaccia in cui sarebbe conveniente restituire una classe unica da molti dei suoi metodi. Questa classe ha senso solo come contenitore per le risposte dai metodi di questa interfaccia.

Quindi, sarebbe conveniente avere una definizione di classe annidata statica, che è associata solo a questa interfaccia, poiché questa interfaccia dovrebbe essere l'unico posto in cui questa classe contenitore dei risultati viene mai creata.


0

Ad esempio tratti (interfaccia simile a smth con metodi implementati) in Groovy. Sono compilati su un'interfaccia che contiene una classe interna in cui sono implementati tutti i metodi.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.