2009-08-21 3 views
7

Diciamo che ho due classi, denominate A e B, che sono associate tra loro in modo tale che è più conveniente se l'oggetto di ogni classe contiene un riferimento all'altro. In altre parole, la classe A ha una variabile "b" di classe B. La classe B ha una variabile "a" di classe A. In questo modo, il codice in ogni classe ha un facile accesso all'altra classe.Java: è possibile avere riferimenti di classe finale reciproci?

C'è un modo per impostare questa associazione come "definitiva"? cioè la variabile b in classe A è finale e variabile a in classe B è finale? Sembra che l'impostazione di questi riferimenti in un costruttore (come sarebbe richiesto dalla parola chiave finale) richiede un tipo di riferimento circolare illogico.

Questa è più una questione concettuale che pratica. Grazie!

risposta

6

Come un altro poster ha sottolineato, è possibile eseguire creando una delle classi responsabili della costruzione dell'altro e passando esso stesso nel costruttore per l'altro oggetto.

Tuttavia, questo si presta a potenziali problemi se si desidera che un'istanza della prima classe corrisponda a un'istanza della seconda classe (che a quanto pare si fa). Un altro oggetto potrebbe potenzialmente passare un riferimento esistente alla prima classe nel costruttore per la seconda classe, consentendo quindi una situazione non valida (l'istanza della seconda classe ora ha un riferimento a un'istanza della prima classe che fa riferimento a uno diverso istanza della seconda classe).

Altri potenziali problemi si presentano quando si considera che il costruttore della seconda classe non può fare riferimento ai membri non inizializzati della prima classe.

Il mio suggerimento è che se le due classi sono così interconnessi che li si vuole avere ciascuno i riferimenti finali verso l'altro, semplicemente la stessa classe fanno. Quindi hai sempre un riferimento finale all'altro oggetto: this.

+0

Combinare le due classi non aiuta. I riferimenti circolari possono e spesso si verificano con oggetti della stessa classe. Considera i nodi in un albero in cui ogni nodo ha un riferimento finale ai suoi genitori e ai suoi figli, o tenta di creare un elenco doppiamente immutabile con riferimenti finali ai nodi successivo e precedente. –

6

Sì, è possibile, se una delle classi è responsabile della creazione dell'istanza dell'altra classe. Il primo costruttore può passare un'istanza di se stesso come parametro per la seconda classe.

public class A { 
    final B b; 
    public A() { 
     b = new B(this); 
    } 
    public B getB() { 
     return b; 
    } 
} 
public class B { 
    final A a; 
    public B(A a) { 
     this.a = a; 
    } 
} 
+4

Sebbene questo approccio possa funzionare, è probabilmente pericoloso poiché il costruttore B riceve un riferimento a un elemento non ancora completamente costruito. Supponiamo, ad esempio, che A abbia un altro campo che è inizializzato * dopo * 'b', e che il costruttore B cerchi di accedervi. Otterrà un oggetto non inizializzato. Lo stesso vale per i metodi di chiamata del costruttore A da B, o se A viene successivamente esteso ... Forse una riprogettazione sarebbe un'opzione migliore. –

+0

Leggermente più conciso è avere una classe una classe interiore dell'altro.(Nota: Come hai reso pubblico il costruttore di 'B', un'altra classe in un altro pacchetto potrebbe costruire un altro' B' per qualsiasi istanza di 'A' (o' null'!).) –

+0

Forse il modo migliore sarebbe quello di rendere entrambi Costruttore di pacchetti di portata, e fornire una sorta di metodo di fabbrica per fornire A. In questo modo nessuno può abusare accidentalmente delle classi. – extraneon

1

se si utilizza un contenitore Di come guice, è possibile acieve questo senza evidente di riferimento che passa all'interno del costruttore - che può essere soggetto a errori come sottolineato in precedenza.

dichiarare la dipendenza a-b e b-a e iniettarne uno in un'altra classe. guice farà un po 'di magia per consentire a entrambi i campi di essere definitivi. fondamentalmente inietterà prima un proxy e metterà il suo delegatore in un secondo momento.

hai bisogno di un esempio di codice per questo?