2012-03-01 17 views
66

Me preguntaba si tiene sentido declarar un método privado como definitivo, y pensé que no tenía sentido. Pero imaginé que hay una situación exclusiva y escribí el código para resolverlo:¿Por qué la clase interna puede anular el método final privado?

public class Boom { 

    private void touchMe() { 
     System.out.println("super::I am not overridable!"); 
    } 

    private class Inner extends Boom { 

     private void touchMe() { 
      super.touchMe(); 
      System.out.println("sub::You suck! I overrided you!"); 
     } 
    } 

    public static void main(String... args) { 
     Boom boom = new Boom(); 
     Boom.Inner inner = boom.new Inner(); 
     inner.touchMe(); 
    } 
} 

Se compiló y funcionó. "Debería hacer TouchMe() final" pensé y lo hizo:

public class Boom { 

    private final void touchMe() { 
     System.out.println("super::I am not overridable!"); 
    } 

    private class Inner extends Boom { 

     private void touchMe() { 
      super.touchMe(); 
      System.out.println("sub::You suck! I overrided you!"); 
     } 
    } 

    public static void main(String... args) { 
     Boom boom = new Boom(); 
     Boom.Inner inner = boom.new Inner(); 
     inner.touchMe(); 
    } 
} 

y también funciona y me

[email protected]:~$ java Boom 
super::I am not overridable! 
sub::You suck! I overrided you! 

qué dice?

+0

Es "ocultar" o "shadowin" o algo así. De alguna manera muestra por qué extender la clase externa es un poco malvado (incluso en enumeraciones, realmente)./Pruebe 'Boom inner = boom.new Inner();' –

+23

Buen ejemplo de por qué debería usar la anotación @Override. Asegúrese de que está anulando el método – Shawn

+0

¿No debería escribir 'super ...' dos veces? * Actualización * No. Mea culpa. Ya veo. – DerMike

Respuesta

87

Los métodos privados no se pueden anular (¡los métodos privados no se heredan!) De hecho, no importa si se declara o no un método privado.

Los dos métodos que se declare, con Boom.touchMe y Boom.Inner.touchMe son dos métodos completamente separadas, que acaba de pasar a compartir el mismo identificador. El hecho de que super.touchMe se refiera a un método diferente de touchMe, es simplemente porque Boom.Inner.touchMesombrasBoom.touchMe (y no porque lo anule).

Esto se puede demostrar en un número de maneras:

  • Como usted descubrió a sí mismo, si cambia los métodos a ser público, el compilador se quejará porque está repente intentando anular una final método.

  • Si mantiene los métodos privados y agrega la anotación @Override, el compilador se quejará.

  • Como alpian señala, si lanzas el objeto Boom.Inner a un objeto Boom (((Boom) inner).touchMe()) la Boom.touchMe se llama (si de hecho fue anulada, el elenco no importaría).

pregunta relacionada:

+13

Puedo estar equivocado en esto, pero creo que un error clave es que 'super.touchMe()' significa "Llamar al método que este método anula". Si bien a menudo funciona de esa manera, realmente significa "Llamar al método' touchMe() 'en la clase que esta clase amplía". Es por eso que puedes llamar a 'super.touchMe()'; también tiene un método (con la misma firma). – corsiKa

+1

Sí, gracias! Lo entiendo ahora. Cuando lo hice público obtuve el error en tiempo de compilación. – chicout

+0

De nada. :-) – aioobe

2

puede invalidar el método porque es private a cada clase.

6

Los métodos privados son invisibles para las subclases o, de hecho, para cualquier otra clase, por lo que pueden tener el mismo nombre, pero no se superan entre sí.

Intenta agregar la anotación @Override - obtendrás un error de compilación.

+1

"Los métodos privados son invisibles para ... cualquier otra clase", excepto y hasta que considere la reflexión. –

+0

Es cierto, pero creo que eso está fuera del alcance de la pregunta original, y no afectaría el problema general. – DNA

8

creo que el hecho de que en realidad hay dos métodos separados que aquí está muy bien demostrado cambiando principal de la siguiente manera:

public static void main(String... args) { 
    Boom boom = new Boom(); 
    Boom.Inner inner = boom.new Inner(); 
    inner.touchMe(); 
    System.out.println("And now cast it..."); 
    ((Boom)(inner)).touchMe(); 
} 

esto ahora impresiones:

super::I am not overridable! 
sub::You suck! I overrided you! 
And now cast it... 
super::I am not overridable! 

y la razón de que la llamada para super funciona en Inner es porque está buscando un método llamado touchMe en su superclase (Boom) que de hecho existe y es visible para Inner ya que está en la misma c muchacha.

1

Acaba de declarar otro método con el mismo nombre. Puede llamar a un miembro privado de la clase porque la clase interna es en sí misma miembro de la clase. Espero que esta modificación lo explique en detalles.

public class Boom { 

    private final void touchMe() { 
     System.out.println("super [touchMe] ::I am not overridable!"); 
    } 

    public void overrideMe(){ 
     System.out.println("super [overrideMe]::I am overridable!"); 
    } 

    private class Inner extends Boom { 

     private void touchMe() { 
      super.touchMe(); 
      System.out.println("sub [touchMe]::You suck! I overrided you!"); 
     } 

     public void overrideMe(){ 
      System.out.println("sub [overrideMe] ::I overrided you!"); 
     } 
    } 

    public static void main(String... args) { 
     Boom boom = new Boom(); 
     Boom.Inner inner = boom.new Inner(); 

     inner.touchMe(); 

     Boom newBoom = inner; 
     newBoom.touchMe(); 
     newBoom.overrideMe(); 
    } 
} 



super [touchMe] ::I am not overridable! 
sub [touchMe]::You suck! I overrided you! 
super [touchMe] ::I am not overridable! 
sub [overrideMe] ::I overrided you! 
Cuestiones relacionadas