Domanda

Come accedere i dalla classe esterna?

  HashSet<Integer> hs=new HashSet<Integer>(){
        int i=30;
    };

posso fare in questo modo

int k=new HashSet<Integer>(){
    int i=30;
}.i;

Ma se ottengo 'i' allora non posso ottenere l'istanza di hashset.Is c'è un modo per ottenere entrambe le cose? La domanda appena fuori curiosity.It non ha molto pratico applications.I voglio solo sapere se si può fare.

È stato utile?

Soluzione

Soluzione 1: sistema di registrazione oggetto

I due frammenti presentato in sostanza ha fatto una scelta fra la memorizzazione del riferimento all'istanza classe anonima appena creato, o per accedere immediatamente il suo campo personalizzato. Facendo uno sembrerebbe perdere la capacità di fare l'altro.

Un modo per raggiungere un compromesso è quello di avere un sistema di registrazione oggetto, e utilizzare un istanza di inizializzazione ( JLS 8,6 ) nella classe anonima di auto-registrarsi per questo sytem.

Ecco un semplice proof-of-concept, utilizzando Object[] per un semplice sistema di registrazione:

    final Object[] registrar = { null };
    int k = new HashSet<Integer>(){
        { registrar[0] = this; }
        int i= 666;
    }.i;
    Set<Integer> set = (Set<Integer>) registrar[0];

    System.out.println(k); // 666
    System.out.println(set.getClass().isAnonymousClass()); // true

In sostanza si usa una 1-elemento Object[], e nel caso di inizializzazione della nostra classe anonima, noi "register" this a questo array. Si noti che questo è solo un concetto proof-of-; nel codice di produzione, utilizza una più robusta e typesafe sistema di registrazione oggetto di questo.


Soluzione 2: Le tuple

Questo approccio funziona bene se la vostra classe anonima può avere più "campi". Semplicemente tutto in valigia in una tuple , avendo cura di includere un riferimento alla this nella classe anonima.

Ecco un semplice proof-of-concept, utilizzando Object[] per una tupla:

    Object[] tuple = new HashSet<Integer>(){
        Object[] tuple = { this, 666, 13, "XXX", "OMG ABUZE" };
    }.tuple;
    Set<Integer> set = (Set<Integer>) tuple[0];
    set.add(null);
    System.out.println(set.getClass().isAnonymousClass()); // true
    System.out.println(Arrays.toString(tuple));
    // [[null], 666, 13, XXX, OMG ABUZE]

Nel codice di produzione, utilizza una classe CustomTuple che è più orientata agli oggetti e typesafe. Si noti che questa è una soluzione analoga al problema "come può il mio metodo di ritorno 2 valori":. Semplicemente restituire 1 valore che cattura tutte quelle informazioni

Altri suggerimenti

Riflessione in soccorso, immagino:

HashSet<Integer> hs = new HashSet<Integer>() {
    int i = 30;
};
int i = hs.getClass().getDeclaredField("i").getInt(hs);
System.out.println(i);

P.S. Mi sento un po 'sporca dopo aver scritto questo.

Ha senso quando si pensa a questo proposito.

L'espressione

new HashSet<Integer>(){
    int i=30;
}

è di tipo java.util.HashSet e java.util.HashSet non ha campo chiamato i, quindi

new HashSet<Integer>(){
   int i=30;
}.i

non verrà compilato. Detto in altro modo, provare a rompere l'espressione composto in modo che il risultato del new viene assegnato a una x variabile, quindi si chiama x.i. Che tipo si potrebbe dare x che permetterebbe x.i di compilare? Non esiste nome del tipo, è una classe anonima.

Si tratta di un "rovescio della medaglia", a classi anonime - possono solo significato ignorare i membri che esistono nel tipo di essere esteso. Se si aggiungono i nuovi membri, che possono essere raggiunte solo attraverso la riflessione.

Non credo che si possa. Non è possibile dichiarare il tipo di una variabile come un tipo anonimo 1 . È possibile introdurre un nome di classe all'interno di un metodo però:

import java.util.*;

public class Test
{
    public static void main(String[] args)
    {
        class Foo extends Hashtable
        {
            int i = 30;
        }

        Foo f = new Foo();
        System.out.println(f.i);
    }
}

E 'orribile (davvero, davvero orribile) e io non credo di aver mai visto usato nel codice di produzione -. Ma funziona


1 C # aggira questo utilizzando var - il compilatore usa l'espressione di inizializzazione per determinare il tipo di variabile. tipi anonimi in Java sono un po 'diversi da quelli in C #, ma se Java aveva qualcosa come var, credo che il codice avrebbe funzionato.

Bene, a mio avviso, c'è sempre il modo di riflessione, ma sembra un po 'eccessivo per me.

E come si imposta la classe per essere forma anonima, non posso vedere nessun altro modo per farlo che la vostra.

classi interne anonime non sono stati progettati per questo scopo, in modo da quello che ricordo non c'è modo che si possa fare. Se si desidera è possibile creare una classe interna "normale".

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