Domanda

Ho appena trovato un'interfaccia nidificata statica nel nostro codice base.

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

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

Qual è la semantica dietro un'interfaccia statica?Cosa cambierebbe se rimuovessi il file static?Perché qualcuno dovrebbe farlo?

È stato utile?

Soluzione

La parola chiave static nell'esempio precedente è ridondante (un'interfaccia annidata è automaticamente "statica") e può essere rimossa senza alcun effetto sulla semantica;Consiglierei di rimuoverlo.Lo stesso vale per "public" sui metodi dell'interfaccia e "public final" sui campi dell'interfaccia: i modificatori sono ridondanti e aggiungono semplicemente confusione al codice sorgente.

In ogni caso, lo sviluppatore sta semplicemente dichiarando un'interfaccia denominata Foo.Bar.Non c'è ulteriore associazione con la classe che lo racchiude, tranne che il codice che non può accedere a Foo non potrà accedere neanche a Foo.Bar.(Dal codice sorgente: il bytecode o la riflessione possono accedere a Foo.Bar anche se Foo è privato del pacchetto!)

È uno stile 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() {...}
});

Altri suggerimenti

Alla domanda è stata data risposta, ma un buon motivo per utilizzare un'interfaccia nidificata è se la sua funzione è direttamente correlata alla classe in cui si trova.Un buon esempio di ciò è a Listener.Se avessi una lezione Foo e volevi che altre classi fossero in grado di ascoltare gli eventi su di essa, potresti dichiarare un'interfaccia denominata FooListener, il che va bene, ma probabilmente sarebbe più chiaro dichiarare un'interfaccia nidificata e implementare le altre classi Foo.Listener (una classe annidata Foo.Event non è male insieme a questo).

Le interfacce dei membri sono implicitamente statiche.Il modificatore statico nel tuo esempio può essere rimosso senza modificare la semantica del codice.Vedi anche le specifiche del linguaggio Java 8.5.1.Dichiarazioni di tipo di membro statico

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

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

In molti sensi, questa non è diversa da una classe interna statica.

La risposta di Jesse è vicina, ma penso che esista un codice migliore per dimostrare perché un'interfaccia interna può essere utile.Guarda il codice qui sotto prima di continuare a leggere.Riesci a scoprire perché l'interfaccia interna è utile?La risposta è che è possibile istanziare la classe DoSomethingAlready Qualunque classe che implementa A e C;non solo la classe concreta Zoo.Naturalmente, questo può essere ottenuto anche se AC non è interno, ma immagina di concatenare nomi più lunghi (non solo A e C) e di farlo per altre combinazioni (ad esempio, A e B, C e B, ecc.) e otterrai facilmente vedere come le cose vanno fuori controllo.Per non parlare del fatto che le persone che esaminano il tuo albero dei sorgenti saranno sopraffatte da interfacce che hanno significato 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;
  }
}

Per rispondere alla tua domanda in modo molto diretto, guarda Map.Entry.

Mappa.Entrata

anche questo può essere utile

Voce di blog sulle interfacce nidificate statiche

In genere vedo classi interne statiche.Le classi interne statiche non possono fare riferimento alle classi che le contengono, mentre le classi non statiche possono farlo.A meno che non ti imbatti in alcune collisioni tra pacchetti (esiste già un'interfaccia chiamata Bar nello stesso pacchetto di Foo), penso che lo renderei un file proprio.Potrebbe anche essere una decisione progettuale quella di rafforzare la connessione logica tra Foo e Bar.Forse l'autore intendeva che Bar fosse utilizzato solo con Foo (anche se un'interfaccia interna statica non lo imporrà, ma solo una connessione logica)

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

l'interfaccia definita all'interno di un'altra interfaccia lo farà statico implicitamente pubblico.

Nel 1998, Philip Wadler suggerì una differenza tra interfacce statiche e interfacce non statiche.

Per quanto posso vedere, l'unica differenza nel creare un'interfaccia non statica è che ora può includere classi interne non statiche;Quindi il cambiamento non renderebbe non valido i programmi Java esistenti.

Ad esempio, ha proposto una soluzione al Problema di espressione, che è la discrepanza tra l'espressione come "quanto può esprimere la tua lingua" da un lato e l'espressione come "i termini che stai cercando di rappresentare nella tua lingua" dall'altro.

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 stato presentato in Java 1.5.0.Quindi tutte le altre risposte sono corrette:non c'è differenza tra le interfacce nidificate statiche e non statiche.

In Java, l'interfaccia/classe statica consente di utilizzare l'interfaccia/classe come una classe di livello superiore, ovvero può essere dichiarata da altre classi.Quindi puoi fare:

class Bob
{
  void FuncA ()
  {
    Foo.Bar foobar;
  }
}

Senza lo statico, quanto sopra non riuscirebbe a compilare.Il vantaggio è che non è necessario un nuovo file sorgente solo per dichiarare l'interfaccia.Associa anche visivamente l'interfaccia Bar alla classe Foo poiché devi scrivere Foo.Bar e implica che la classe Foo faccia qualcosa con le istanze di Foo.Bar.

Una descrizione dei tipi di classe in Java.

Statico significa che qualsiasi parte della classe del pacchetto (progetto) può accedervi senza utilizzare un puntatore.Questo può essere utile o ostacolante a seconda della situazione.

L'esempio perfetto dell'utilità dei metodi "statici" è la classe Math.Tutti i metodi in Math sono statici.Ciò significa che non devi fare di tutto, creare una nuova istanza, dichiarare variabili e memorizzarle in ancora più variabili, puoi semplicemente inserire i tuoi dati e ottenere un risultato.

L'elettricità statica non è sempre così utile.Se, ad esempio, stai effettuando un confronto tra casi, potresti voler archiviare i dati in diversi modi.Non è possibile creare tre metodi statici con firme identiche.Hai bisogno di 3 istanze diverse, non statiche, quindi puoi confrontare, perché se è statico, i dati non cambieranno insieme all'input.

I metodi statici sono utili per rendimenti una tantum e calcoli rapidi o dati facilmente ottenibili.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top