2011-12-09 18 views
8

En el siguiente ejemplo:Llamar a un método reemplazado de un constructor

class Base {  
    int x=10; 

    Base() {  
     show(); 
    } 

    void show() { 
     System.out.print ("Base Show " +x + " "); 
    } 
} 

class Child extends Base { 
    int x=20; 

    Child() { 
     show(); 
    } 

    void show() {  
     System.out.print("Child Show " + x +" ") ; 
    } 

    public static void main(String s[ ]) { 
     Base obj = new Child(); 
    } 
} 
  • ¿Por qué es la salida como se muestra a continuación
Child Show 0 Child Show 20 
  • pensé Los constructores pueden solo acceder a los miembros de la instancia una vez que sea su súper constructor s completado

Creo que lo que está sucediendo aquí es que el super constructor llama al método show() del niño porque este método fue anulado en Child. ya que ha sido anulado pero ¿por qué es el valor de x 0 y por qué es capaz de acceder a este método antes de que el super constructor se haya completado?

+0

¿Está activado el mecanismo de manipulación virtual durante la construcción de un objeto? Dudo que no lo sea. – Mahesh

+0

En C++ esto puede causar un bloqueo. –

+3

Effective Java es un gran recurso de Java y entra en esto con gran detalle. Del Elemento 17: "*** Los constructores no deben invocar métodos invalidables **, directa o indirectamente (...) Si el método de anulación depende de cualquier inicialización realizada por el constructor de la subclase, el método no se comportará como se espera. * "Si tienes el libro a la mano, recomiendo leer este artículo. –

Respuesta

11

Creo que lo que está sucediendo aquí es que el super constructor está llamando al método show() del niño porque este método fue anulado en Child.

Eso es correcto

pero ¿por qué es el valor de x 0

porque no está inicializado (x del niño)

y por qué es capaz para acceder a este método antes de que el super constructor se haya completado?

Es exactamente por eso que en un constructor nunca debe llamar a un método, que puede ser anulado (público no final y protegido).

Editar:

Lo extraño aquí es que todo tiene visibilidad predeterminada/package-privada. Esto puede tener algunos efectos extraños. Ver: http://www.cooljeff.co.uk/2009/05/03/the-subtleties-of-overriding-package-private-methods/

Recomiendo evitar los métodos de anulación con visibilidad predeterminada si es posible (puede evitar esto al declararlos como definitivos).

+1

+1 La secuencia es main -> Child() -> Base() -> Child.show() [x aún no se ha inicializado] -> Base.show() [precedido por Base.x = 20] – stacker

+0

No, el la secuencia es main -> Base() -> Child.show() [x aún no inicializado] -> Child() [Child.x = 20] -> Child.show() – Puce

+0

hace la variable x en la clase Child tiene se le ha dado un valor predeterminado de 0 cuando se ha completado la clase Object? Porque hasta donde puedo recordar aquí está la secuencia: new Child() -> Base() -> Object -> Child's implementation of show() ... – anathema

6

Puede llamar a los métodos overriden de constructores, pero es mal y no debería. Usted ilustró la razón por la que esto es malo: la clase derivada no tiene la oportunidad de inicializarse, por lo que se usarán campos no inicializados; en su ejemplo, el valor predeterminado para int x es 0, por eso está imprimiendo 0.

Cuestiones relacionadas