2012-08-16 13 views
5

He preguntado sobre cómo obtener una instancia única de clase de otra clase recientemente.Diferentes referencias de objetos para el mismo objeto (?)

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

lo tanto, yo estoy tratando de hacer que funcione:

Mi 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); 
    } 

} 

Mi 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; 
    } 

} 

El problema es que main método devuelve diferente referencias de objetos.

[email protected] 
[email protected] 

¿Qué pasa con mi código?

+0

Se utiliza una embarazos únicos y otras formas de estado global, eso es lo que está mal con él. –

+0

¿Por qué no utilizar enumeraciones cuando necesita Singletons? –

Respuesta

7

Esto es lo que sucede:

  • el programa llama primero Application application1 = getSharedApplication();
  • que a su vez llama al método estático que llama new Application() - esa llamada tiene que cargar la clase View, que es miembro de Application.
  • La clase de vista se carga y su miembro estático se inicializa y ejecuta getSharedApplication(); (tenga en cuenta que en este momento, _application sigue siendo nulo). Eso también crea un new Application()

Ahora tiene 2 instancias de aplicación.

Tenga en cuenta que si agrega View v = new View(); como la primera línea de su main, solo tiene una instancia de Application (que se carga una vez desde la variable estática de View). Eso tiene sentido cuando lo piensas mucho pero no es muy intuitivo ...

+0

Hermoso. Este ejemplo debe ir en la página de "¿Por qué Singleton es casi siempre una mala idea"? – Jochen

+0

El estado global (variables estáticas) es difícil de razonar, especialmente cuando hay referencias cíclicas. – assylias

+1

Los singleton no son una mala idea, pero se pueden implementar mal, ya que están aquí. –

4

La respuesta general a estas preguntas es: ¡Use un depurador! Por ejemplo, puede establecer un punto de interrupción en el constructor de Application, ejecutar su programa e inspeccionar la pila cuando el constructor se ejecute por segunda vez.

Si lo hace, se le nota algo como esto:

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

Es decir, el punto de vista quiere obtener la aplicación compartida antes de la aplicación compartida ha sido construido totalmente (y antes de que éste se almacena en el campo estático).

0

El método getSharedApplication() debe usar la palabra clave sincronizada. De lo contrario, dos subprocesos pueden entrar en el primer bloque de instrucción if y ambos crean diferentes variables.

No estoy seguro de si eso es lo que está sucediendo aquí. Intente agregar declaraciones de depuración/impresión en todas partes para que pueda seguir lo que realmente está sucediendo.

+2

Solo hay un hilo en este ejemplo. – assylias

+0

@assylias Lo sé, pero él está pidiendo problemas más adelante si el método no está sincronizado. –

+0

Haces un punto justo: solo digo que no es la causa del problema. – assylias

1

Si cambia la inicialización de vista, como a continuación

public static Application getSharedApplication() { 

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

Va a encontrar un solo caso se está creando. Motivo por el que está creando una instancia de Vista antes de que la Aplicación se haya inicializado por completo. Porque las variables estáticas se cargan cuando se solicita la clase por primera vez, por lo que este comportamiento está sucediendo.

De todos modos he aprendido que nunca se haga esto :) Gracias :)

+0

¡Hm, eso funciona! :) –

Cuestiones relacionadas