2009-04-17 20 views
110

In Java, le classi nidificate possono essere sia static oppure no. Se sono static, non contengono un riferimento al puntatore dell'istanza contenente (non sono più chiamate classi interne, sono chiamate classi nidificate).È possibile rendere statiche le classi interne anonime in Java?

Dimenticandosi di creare una classe nidificata static quando non ha bisogno di quella referenza può portare a problemi con la garbage collection o l'analisi di escape.

È possibile creare anche una classe interna anonima static? Oppure il compilatore lo calcola automaticamente (che potrebbe, perché non ci possono essere sottoclassi)?

Per esempio, se faccio un comparatore anonima, ho quasi mai bisogno il riferimento verso l'esterno:

Collections.sort(list, new Comparator<String>(){ 
     int compare(String a, String b){ 
      return a.toUpperCase().compareTo(b.toUpperCase()); 
     } 
    } 
+0

Quali sono i problemi con "garbage collection o escape analysis" quando si dimentica di rendere statica una classe interna? Ho pensato che questo riguardasse solo le prestazioni ... –

+13

L'istanza della classe interna mantiene vivo un riferimento alla sua istanza esterna, anche se non ne hai bisogno. Questo potrebbe impedire che la roba venga raccolta dalla spazzatura. Immaginate un oggetto fabbrica (pesante in termini di risorse) che crea istanze leggere di qualcosa. Dopo che la fabbrica ha fatto il suo lavoro (ad esempio durante l'avvio dell'applicazione), potrebbe essere smaltita, ma funziona solo se le cose che ha creato non si ricollegano. – Thilo

+0

Lo so, questo è solo un esempio, ma poiché è ricorrente, si dovrebbe menzionare che 'Collections.sort (list, String.CASE_INSENSITIVE_ORDER)' funziona da Java 2, leggi, poiché esiste l'API Collection ... – Holger

risposta

126

No, non è possibile, e no, il compilatore non riesce a capirlo. Ecco perché FindBugs suggerisce sempre di modificare le classi interne anonime alle classi nidificate static se non utilizzano il loro riferimento implicito this.

Edit: Tom Hawtin - tackline dice che se la classe anonima viene creato in un contesto statico (ad esempio nel metodo main), la classe anonima è infatti static. Ma la JLS disagrees:

una classe anonima non è mai abstract (§8.1.1.1). Una classe anonima è sempre una classe interiore (§8.1.3); non è mai static (§8.1.1, §8.5.1). Una classe anonima è sempre implicitamente final (§8.1.1.2).

Roedy Java Glossario di Green says that il fatto che le classi anonime sono consentiti in un contesto statico dipende dall'implementazione:

Se si vuole confondere coloro mantenere il vostro codice, Wags hanno scoperto javac.exe permetterà anonima classi all'interno del metodo static e dei metodi static, anche se la specifica della lingua dice che le classi anonime non sono mai static. Queste classi anonime, ovviamente, non hanno accesso ai campi di istanza dell'oggetto. Non consiglio di farlo. La funzione potrebbe essere estratta in qualsiasi momento.

Edit 2: Il JLS copre in realtà contesti statici più esplicitamente in §15.9.2:

Let C essere la classe viene istanziato, e lasciare che i essere l'istanza in fase di creazione. Se C è una classe interna, quindi i potrebbe avere un'istanza immediatamente allegata. L'istanza immediatamente allegata di i (§8.1.3) è determinata come segue.

  • Se C è una classe anonima, quindi:
    • Se l'espressione creazione dell'istanza classe avviene in un contesto statico (§8.1.3), quindi i è non immediatamente racchiude esempio.
    • In caso contrario, l'istanza immediatamente allegata di i è this.

Quindi una classe anonima in un contesto statico è più o meno equivalente a una classe annidata static in quanto non mantiene un riferimento alla classe contenitrice, anche se non è tecnicamente una classe static.

+18

+1 per FindBugs - ogni sviluppatore Java dovrebbe avere questo nella loro build. –

+12

Questo è molto sfortunato, perché significa che potresti voler evitare questa sintassi, altrimenti quasi concisa, per motivi di prestazioni. – Thilo

+2

JLS 3rd Ed si occupa del caso di classi interne in contesti statici. Non sono statici nel senso di JLS, ma sono statici nel senso indicato nella domanda. –

6

classi interiore non può essere statica - una classe innestata statica non è una classe interna. The Java tutorial talks about it here.

+1

I ho aggiornato la domanda con un riferimento alla nomenclatura ufficiale. – Thilo

12

Tipo di. Una classe interiore anonima creata in un metodo statico sarà evidentemente statica perché non esiste una fonte per questo esterno.

Esistono alcune differenze tecniche tra le classi interne in contesti statici e classi nidificate statiche. Se sei interessato, leggi il JLS 3rd Ed.

+0

Oh, ottimo punto. –

+0

In realtà, riprendo quello; il JLS non è d'accordo. http://java.sun.com/docs/books/jls/third%5Fedition/html/expressions.html#15.9.5: "Una classe anonima è sempre una classe interiore, non è mai statica." –

+1

statico in un senso diverso da quello nella domanda. –

14

Penso che ci sia un po 'di confusione nella nomenclatura qui, che è certamente troppo sciocca e confusa.

Qualunque cosa tu li chiami, questi schemi (e un paio di varianti con diversa visibilità) sono possibile, normale, Java legale:

public class MyClass { 
    class MyClassInside { 
    } 
} 

public class MyClass { 
    public static class MyClassInside { 
    } 
} 

public class MyClass { 
    public void method() { 
    JComponent jc = new JComponent() { 
     ... 
    } 
    } 
} 

public class MyClass { 
    public static void myStaticMethod() { 
    JComponent jc = new JComponent() { 
     ... 
    } 
    } 
} 

Essi sono soddisfatti nella specifica lingua (se si' veramente infastidito, vedi la sezione 15.9.5.1 per quella all'interno del metodo statico).

Ma questa citazione è semplicemente sbagliato:

javac.exe permetterà anonimi classi all'interno del codice di inizializzazione statico e metodi statici, anche se le specifiche lingua dice di anonimi classi non sono mai statica

credo che l'autore citato confonde il parola chiave static con statico contesto. (Certo, anche il JLS è un po 'confuso da questo punto di vista.)

Onestamente, tutti i modelli qui sopra vanno bene (qualunque cosa tu li chiami "nidificati", "interiori", "anonimi" qualunque cosa ...). In realtà nessuno rimuoverà improvvisamente questa funzionalità nella prossima versione di Java. Onestamente!

+2

"(Certo, anche il JLS è un po 'confuso da questo punto di vista.)" Hai capito bene. Sembrava strano dire che dipende dall'implementazione, ma non ricordo di aver mai visto errori evidenti nel Glossario Java. D'ora in poi, lo prendo con un pizzico di sale. –

+2

In realtà non stiamo parlando di nessuno degli schemi. Intendiamo che la classe nidificata anonima è statica. Cioè aggiungi un "statico" tra 'new' e' JComponent' nel tuo terzo esempio. – Timmmm

+0

Ho aggiunto un chiarimento alla domanda originale per mostrare cosa si desidera. – Timmmm

-3

Sulla nota di rendere statica una classe interna anonima chiamandole all'interno di un metodo statico.

Questo in realtà non rimuove il riferimento. Puoi testare questo cercando di serializzare la classe anonima e non rendere serializzabile la classe che la include.

+5

-1: la creazione di una classe anonima all'interno di un metodo statico in realtà * fa * rimuove il riferimento alla classe esterna. Puoi testare questo cercando di serializzare la classe anonima e non rendere serializzabile la classe che la include. (L'ho appena fatto.) –

0

le classi interne anonime non sono mai statiche (non possono dichiarare metodi statici o campi statici non finali), ma se sono definite in un contesto statico (metodo statico o campo statico) si comportano come statiche nel senso che non possono accedere ai membri non statici (cioè di istanza) della classe che li include (come tutto il resto da un contesto statico)

Problemi correlati