it-swarm.it

Perché un'interfaccia nidificata statica dovrebbe essere utilizzata in Java?

Ho appena trovato un'interfaccia nidificata statica nella nostra base di codice.

class Foo {
    public static interface Bar {
        /* snip */
    }
    /* snip */
}

Non l'ho mai visto prima. Lo sviluppatore originale è fuori portata. Pertanto devo chiedere SO:

Quali sono le semantiche dietro un'interfaccia statica? Cosa cambierebbe se rimuovessi static? Perché qualcuno dovrebbe farlo?

231
Mo.

La parola chiave statica nell'esempio sopra è ridondante (un'interfaccia nidificata è automaticamente "statica") e può essere rimossa senza alcun effetto sulla semantica; Consiglierei di essere rimosso. Lo stesso vale per "pubblico" sui metodi di interfaccia e "pubblico finale" sui campi di interfaccia: i modificatori sono ridondanti e aggiungono solo disordine al codice sorgente.

Ad ogni modo, lo sviluppatore sta semplicemente dichiarando un'interfaccia chiamata Foo.Bar. Non esiste alcuna ulteriore associazione con la classe che lo racchiude, ad eccezione del fatto che il codice che non può accedere a Foo non sarà in grado di accedere a Foo.Bar. (Dal codice sorgente - bytecode o reflection possono accedere a Foo.Bar anche se Foo è un pacchetto privato!)

È accettabile creare un'interfaccia nidificata in questo modo se si prevede che venga utilizzata solo dalla classe esterna, in modo da non creare un nuovo nome di livello superiore. Per esempio:

public class Foo {
    public interface Bar {
        void callback();
    }
    public static void registerCallback(Bar bar) {...}
}
// ...elsewhere...
Foo.registerCallback(new Foo.Bar() {
    public void callback() {...}
});
291
Jesse Glick

Alla domanda è stata data una risposta, ma un buon motivo per usare un'interfaccia nidificata è se la sua funzione è direttamente correlata alla classe in cui si trova. Un buon esempio di ciò è un Listener. Se avevi una classe Foo e volevi che altre classi potessero ascoltare eventi su di essa, potresti dichiarare un'interfaccia chiamata FooListener, che è ok, ma probabilmente sarebbe più chiaro per dichiarare un'interfaccia nidificata e avere quelle altre classi implementare Foo.Listener (una classe nidificata Foo.Event non è male insieme a questo).

71
ColinD

Le interfacce dei membri sono implicitamente statiche. Il modificatore statico nel tuo esempio può essere rimosso senza cambiare la semantica del codice. Vedi anche il Java Language Specification 8.5.1. Dichiarazioni del tipo di membro statico

14
Bas Leijdekkers

Un'interfaccia interna deve essere statica per poter accedere. L'interfaccia non è associata alle istanze della classe, ma alla classe stessa, quindi sarebbe possibile accedervi con Foo.Bar, così:

public class Baz implements Foo.Bar {
   ...
}

Nella maggior parte dei modi, questo non è diverso da una classe interna statica.

9

La risposta di Jesse è vicina, ma penso che ci sia un codice migliore per dimostrare perché un'interfaccia interna può essere utile. Guarda il codice qui sotto prima di continuare a leggere. Riesci a capire perché l'interfaccia interna è utile? La risposta è che la classe DoSomethingAl già può essere istanziata qualunque classe che implementa A e C; non solo lo zoo di classe concreto. Naturalmente, questo può essere ottenuto anche se AC non è interno, ma immagina di concatenare nomi più lunghi (non solo A e C), e farlo per altre combinazioni (diciamo, A e B, C e B, ecc.) E tu facilmente guarda come le cose vanno fuori controllo. Per non parlare del fatto che le persone che recensiscono il tuo albero dei sorgenti saranno sopraffatte da interfacce significative solo in una classe. Quindi, per riassumere, un'interfaccia interna consente la costruzione di tipi personalizzati e ne migliora l'incapsulamento.

class ConcreteA implements A {
 :
}

class ConcreteB implements B {
 :
}

class ConcreteC implements C {
 :
}

class Zoo implements A, C {
 :
}

class DoSomethingAlready {
  interface AC extends A, C { }

  private final AC ac;

  DoSomethingAlready(AC ac) {
    this.ac = ac;
  }
}
6
user1982892

Per rispondere alla tua domanda molto direttamente, guarda Map.Entry.

Map.Entry

anche questo può essere utile

Voce statica del blog Sulle interfacce nidificate

3
Henry B

Nel 1998, Philip Wadler ha suggerito una differenza tra interfacce statiche e interfacce non statiche.

Per quanto posso vedere, l'unica differenza nel rendere un'interfaccia non statica è che ora può includere classi interne non statiche; quindi la modifica non renderebbe non valido alcun programma Java esistente).

Ad esempio, ha proposto una soluzione a Expression Problem , che è la discrepanza tra espressione come "quanto può esprimere la tua lingua" da un lato ed espressione come "i termini che stai cercando di rappresentare la tua lingua "d'altra parte.

Un esempio della differenza tra interfacce nidificate statiche e non statiche può essere visto in il suo codice di esempio :

// This code does NOT compile
class LangF<This extends LangF<This>> {
    interface Visitor<R> {
        public R forNum(int n);
    }

    interface Exp {
        // since Exp is non-static, it can refer to the type bound to This
        public <R> R visit(This.Visitor<R> v);
    }
}

Il suo suggerimento non è mai arrivato in Java 1.5.0. Quindi, tutte le altre risposte sono corrette: non c'è differenza con le interfacce nidificate statiche e non statiche.

0
Pindatjuh

Se cambi la classe Foo nell'interfaccia Foo, anche la parola chiave "pubblica" nell'esempio sopra sarà ridondante perché

l'interfaccia definita all'interno di un'altra interfaccia sarà implicitamente pubblica statica.

0
Danylo Volokh

In genere vedo classi interne statiche. Le classi interne statiche non possono fare riferimento alle classi contenenti dove possono le classi non statiche. A meno che tu non stia imbattendo in alcune collisioni di pacchetti (esiste già un'interfaccia chiamata Bar nello stesso pacchetto di Foo), penso che lo farei nel suo file. Potrebbe anche essere una decisione progettuale far valere la connessione logica tra Foo e Bar. Forse l'autore voleva che Bar venisse usato solo con Foo (sebbene un'interfaccia interna statica non lo imponga, solo una connessione logica)

0
basszero