È possibile rendere statiche le classi interne anonime in Java?


123

In Java, le classi nidificate possono essere statico meno. Se lo sono static, non contengono un riferimento al puntatore dell'istanza che lo contiene (inoltre non sono più chiamate classi interne, sono chiamate classi annidate).

Dimenticare di creare una classe annidata staticquando non ha bisogno di quel riferimento può portare a problemi con la raccolta dei rifiuti o l'analisi dell'escape.

È possibile creare anche una classe interna anonima static? O il compilatore lo capisce automaticamente (cosa che potrebbe, perché non possono esserci sottoclassi)?

Ad esempio, se realizzo un comparatore anonimo, non ho quasi mai bisogno del riferimento all'esterno:

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

Quali sono i problemi con "la raccolta dei rifiuti o l'analisi di fuga" quando si dimentica di rendere statica una classe interna? Pensavo che si
trattasse

17
L'istanza della classe interna mantiene vivo un riferimento alla sua istanza esterna, anche se non ne hai bisogno. Ciò potrebbe impedire che le cose vengano raccolte nella spazzatura. Immagina un oggetto di fabbrica (ricco di risorse) che crea istanze leggere di qualcosa. Dopo che la fabbrica ha svolto il suo lavoro (ad esempio durante l'avvio dell'applicazione), potrebbe essere eliminata, ma funziona solo se le cose che ha creato non si ricollegano.
Thilo

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

Risposte:


138

No, non puoi e no, il compilatore non riesce a capirlo. Questo è il motivo per cui FindBugs suggerisce sempre di cambiare le classi interne anonime in classi staticannidate denominate se non usano il loro thisriferimento implicito .

Modifica: Tom Hawtin - tackline dice che se la classe anonima viene creata in un contesto statico (ad esempio nel mainmetodo), la classe anonima è in effetti static. Ma il JLS non è d'accordo :

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

Il glossario Java di Roedy Green afferma che il fatto che le classi anonime siano consentite in un contesto statico dipende dall'implementazione:

Se vuoi sconcertare coloro che mantengono il tuo codice, i wags hanno scoperto javac.execonsentiranno classi anonime all'interno del staticcodice e dei staticmetodi di init , anche se le specifiche del linguaggio dicono che le classi anonime non lo sono mai static. Queste classi anonime, ovviamente, non hanno accesso ai campi istanza dell'oggetto. Non consiglio di farlo. La funzione può essere ritirata in qualsiasi momento.

Modifica 2: JLS copre effettivamente i contesti statici in modo più esplicito in §15.9.2 :

Sia C la classe che viene istanziata e io l'istanza che viene creata. Se C è una classe interna, potrei avere un'istanza che lo racchiude immediatamente. L'istanza immediatamente allegata di i (§8.1.3) è determinata come segue.

  • Se C è una classe anonima, allora:
    • Se l'espressione di creazione dell'istanza di classe si verifica in un contesto statico (§8.1.3), allora i non ha un'istanza che racchiude immediatamente.
    • Altrimenti, l'istanza che racchiude immediatamente i è this.

Quindi una classe anonima in un contesto statico è più o meno equivalente a una staticclasse nidificata in quanto non mantiene un riferimento alla classe che la racchiude, anche se tecnicamente non è una staticclasse.


19
+1 per FindBugs: ogni sviluppatore Java dovrebbe averlo nella propria build.
Andrew Duffy

13
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 delle classi interne in contesti statici. Non sono statici nel senso JLS, ma sono statici nel senso dato nella domanda.
Tom Hawtin - tackline

6
Ecco un esempio di come dipende dall'implementazione: questo codice viene stampato trueutilizzando javac (sun-jdk-1.7.0_10) e falseutilizzando il compilatore Eclipse.
Paul Bellora

1
@MichaelMyers Ho provato a simulare i FindBugs che mi avvisano di fare un Anonymous Inner senza usare il riferimento "this" e non succede nulla. Puoi dimostrare come FindBugs ti avvisa come hai detto all'inizio della tua risposta? Basta incollare qualche link o cosa mai.
Thufir Hawat

15

Tipo. Una classe interna anonima creata in un metodo statico sarà ovviamente effettivamente statica perché non esiste una sorgente per un this esterno.

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


In realtà, lo riprendo; il JLS non è d'accordo. java.sun.com/docs/books/jls/third%5Fedition/html/… : "Una classe anonima è sempre una classe interna; non è mai statica."
Michael Myers

1
statico in un senso diverso da quello della domanda.
Tom Hawtin - tackline

1
Ho aggiunto un piccolo chiarimento.
Tom Hawtin - tackline

15

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

Comunque li chiami, questi pattern (e alcune variazioni con visibilità diversa) sono tutti Java possibili, normali e legali:

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() {
      ...
    }
  }
}

Sono soddisfatti nelle specifiche del linguaggio (se sei davvero infastidito, vedi la sezione 15.9.5.1 per quello all'interno del metodo statico).

Ma questa citazione è semplicemente sbagliata :

javac.exe consentirà classi anonime all'interno di codice init statico e metodi statici, anche se le specifiche della lingua dicono che le classi anonime non sono mai statiche

Penso che l'autore citato stia confondendo la parola chiave statica con il contesto statico . (Certo, anche il JLS è un po 'confuso sotto questo aspetto.)

Onestamente, tutti gli schemi sopra vanno bene (qualunque cosa tu li chiami "annidati", "interni", "anonimi" qualunque cosa ...). In realtà, nessuno rimuoverà improvvisamente questa funzionalità nella prossima versione di Java. Onestamente!


2
"(Certo, anche il JLS è un po 'confuso sotto questo aspetto.)" Hai capito bene. Sembrava strano dire che dipende dall'implementazione, ma non ricordo di aver visto errori evidenti nel glossario Java prima. D'ora in poi, lo prendo con le pinze.
Michael Myers

2
In realtà non stiamo parlando di nessuno degli schemi. Intendiamo che la classe annidata anonima è statica. Ad esempio, aggiungi una "statica" tra newe JComponentnel tuo terzo esempio.
Timmmm

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

@MichaelMyers, La dettatura in JLS deve sempre essere interpretata.
Pacerier


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è istanza) della classe che lo racchiude (come tutto il resto da un contesto statico)


-3

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

Questo in realtà non rimuove il riferimento. Puoi verificarlo provando a serializzare la classe anonima e non rendendo serializzabile la classe che la racchiude.


5
-1: Creazione di una classe anonima all'interno di un metodo statico in realtà non rimuovere il riferimento alla classe esterna. Puoi verificarlo provando a serializzare la classe anonima e non rendendo serializzabile la classe che la racchiude. (L'ho appena fatto.)
Christian Semrau
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.