2012-08-16 15 views
5

Ho chiesto di ottenere di recente un'istanza di classe univoca da un'altra classe.Riferimenti a oggetti diversi per lo stesso oggetto (?)

(How to get specific instance of class from another class in Java?)

Quindi, sto cercando di farlo funzionare:

mio Application:

public class Application 
{ 

    // I will always have only one instance of Application 

    private static Application _application; 

    // Every instance of Application (one in my case) should have its own View 

    private View view; 

    // Constructor for new instance of Application 

    private Application() 
    { 
     view = new View(); 
    } 

    // Getter for my unique instance of Application 

    public static Application getSharedApplication() 
    { 
     if (_application == null) 
      _application = new Application(); 
     return _application; 
    } 

    // Main class 

    public static void main(String[] args) 
    { 
     // So I'm accessing my instance of Application 
     Application application1 = getSharedApplication(); 

     // Here is object reference 
     System.out.println(application1); 

     // And now I'm accessing the same instance of Application through instance of View 
     Application application2 = application1.view.getApplication(); 

     // Here is object reference 
     System.out.println(application2); 
    } 

} 

mio View:

public class View 
{ 

    // I'm accessing my instance of Application again 

    public static Application application = Application.getSharedApplication(); 

    // This method should return my unique instance of Application 

    public Application getApplication() 
    { 
     return application; 
    } 

} 

Il problema è che main il metodo restituisce diversi riferimenti a oggetti.

[email protected] 
[email protected] 

Cosa c'è di sbagliato nel mio codice?

+0

Esso utilizza un single e altre forme di stato globale, questo è ciò che è sbagliato con esso. –

+0

Perché non usare le enumerazioni quando hai bisogno di Singletons? –

risposta

7

Ecco cosa succede:

  • il programma prima chiama Application application1 = getSharedApplication();
  • che a sua volta chiama il metodo statico che chiama new Application() - quella chiamata ha bisogno di caricare la classe View, che è un membro del Application.
  • la classe View viene caricata e il suo membro statico viene inizializzato e viene eseguito getSharedApplication(); (notare che in questa fase, _application è ancora null). Ciò crea anche

Ora hai 2 istanze di applicazione.

Si noti che se si aggiunge View v = new View(); come la prima linea del vostro principale, si dispone di una sola istanza di applicazione (che viene caricato una volta dalla variabile statica di vista). Questo ha senso quando ci pensi bene ma non è molto intuitivo ...

+0

Bello. Questo esempio dovrebbe andare sulla pagina per "Perché Singleton è quasi sempre una cattiva idea"! – Jochen

+0

Lo stato globale (variabili statiche) è difficile da ragionare, specialmente quando ci sono riferimenti ciclici! – assylias

+1

I singleton non sono una cattiva idea, ma possono essere implementati male, così come sono qui. –

4

La risposta generale a tali domande è: utilizzare un debugger! Ad esempio, è possibile impostare un punto di interruzione nel costruttore di Application, eseguire il programma e ispezionare lo stack quando il costruttore viene eseguito per la seconda volta.

Se si esegue questa operazione, si noterà qualcosa di simile:

Application.<init>() line: 21 
Application.getSharedApplication() line: 31 
View.<clinit>() line: 59  
Application.<init>() line: 23 
Application.getSharedApplication() line: 31 

Cioè, la vista vuole ottenere l'applicazione condivisa prima che l'applicazione condivisa è stato completamente costruito (e prima che quest'ultimo viene memorizzato nel campo statico).

0

Il metodo getSharedApplication() dovrebbe usare la parola chiave sincronizzata. In caso contrario, due thread possono immettere il primo blocco di istruzioni if ​​ed entrambi creano variabili diverse.

Non sono sicuro se questo è ciò che sta accadendo qui. Prova ad aggiungere dichiarazioni di debug/print ovunque in modo da poter seguire ciò che sta realmente accadendo.

+2

C'è solo una discussione in questo esempio. – assylias

+0

@assylias Lo so, ma in seguito chiede dei guai se il metodo non è sincronizzato. –

+0

Tu fai un equo punto - sto solo dicendo che non è la causa del problema. – assylias

1

Se si modifica l'inizializzazione di vista come qui di seguito

public static Application getSharedApplication() { 

    if(_application == null) 
    { 
     _application = new Application(); 
     view = new View(); 
    } 

Troverete una sola istanza è sempre creato. Il motivo è che si sta creando l'istanza View prima che l'applicazione sia completamente inizializzata. Perché le variabili statiche vengono caricate quando la classe viene richiesta per la prima volta, quindi questo comportamento sta accadendo.

Comunque ho imparato che mai fare questo :) Grazie :)

+0

Hm, funziona! :) –