Risposte:
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 ...).
interface
s non può avere classi interne. Puoi omettere il static
modificatore di una interface
classe nidificata, ma è comunque una classe nidificata, non una classe interna.
B
classe è 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
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.
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.
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.
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).
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;
}
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);
...
}
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?
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.
Ho trovato un utilizzo per questo tipo di costrutto.
Hai accesso a tutte le costanti raggruppate; in questo caso il nome della classe funge da spazio dei nomi.
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.