Can I override a static method?
Mucha gente ha oído que no se puede reemplazar un método estático. Esto es verdad - no puedes. Sin embargo, es posible escribir código como este:
class Foo {
public static void method() {
System.out.println("in Foo");
}
}
class Bar extends Foo {
public static void method() {
System.out.println("in Bar");
}
}
Esto compila y funciona muy bien. ¿No es un ejemplo de método estático que reemplaza a otro método estático? La respuesta es no; es un ejemplo de método estático que oculta otro método estático. Si intentas anular un método estático, el compilador en realidad no te detiene, simplemente no hace lo que crees que hace.
¿Cuál es la diferencia?
En pocas palabras, cuando anula un método, aún obtiene los beneficios del polimorfismo en tiempo de ejecución, y cuando se esconde, no lo hace. ¿Entonces que significa eso?Echar un vistazo a este código:
class Foo {
public static void classMethod() {
System.out.println("classMethod() in Foo");
}
public void instanceMethod() {
System.out.println("instanceMethod() in Foo");
}
}
class Bar extends Foo {
public static void classMethod() {
System.out.println("classMethod() in Bar");
}
public void instanceMethod() {
System.out.println("instanceMethod() in Bar");
}
}
class Test {
public static void main(String[] args) {
Foo f = new Bar();
f.instanceMethod();
f.classMethod();
}
}
Si ejecuta este, la salida es
instanceMethod() en la barra de
classmethod() en Foo
¿Por qué nos instanceMethod de Bar, pero classMethod() de Foo? ¿No estamos usando la misma instancia f para acceder a ambos? Sí, lo somos, pero dado que uno es primordial y el otro se está ocultando, vemos un comportamiento diferente.
Dado que instanceMethod() es (drum roll por favor ...) un método de instancia, en el que Bar reemplaza el método de Foo, en tiempo de ejecución la JVM usa la clase real de la instancia f para determinar qué método ejecutar. Aunque f se declaró como un Foo, la instancia real que creamos fue una nueva barra(). Por lo tanto en tiempo de ejecución, la JVM encuentra que f es una instancia de la barra, y por lo que llama instanceMethod() en la barra en lugar de la de Foo. Así es como funciona normalmente Java, por ejemplo, los métodos.
Con classmethod() sin embargo. ya que (ejem) es un método de clase, el compilador y la JVM no esperan necesitar una instancia real para invocar el método. E incluso si proporciona uno (lo cual hicimos: la instancia mencionada por f), la JVM nunca lo verá. El compilador solo verá el tipo declarado de la referencia y usará ese tipo declarado para determinar, en tiempo de compilación, a qué método llamar. Puesto que f es declarado como tipo Foo, el compilador mira f.classMethod() y decide que quiere decir Foo.classMethod. No importa que la instancia referida por f sea en realidad una barra; para los métodos estáticos, el compilador solo usa el tipo declarado de la referencia. A eso nos referimos cuando decimos que un método estático no tiene un polimorfismo en tiempo de ejecución.
Como los métodos de instancia y los métodos de clase tienen esta importante diferencia en el comportamiento, utilizamos términos diferentes - "anulación" para los métodos de ejemplo y "ocultación" para los métodos de clase - para distinguir entre los dos casos. Y cuando decimos que no se puede reemplazar un método estático, lo que significa es que incluso si se escribe el código que parece que se está reemplazando un método estático (como el primer Foo y Bar en la parte superior de esta página) - no lo hará comportarse como un método anulado para más referirse this
No debe ser llamando a métodos estáticos desde un objeto en primer lugar, debería llamarlo desde la clase. –