2010-05-14 18 views
10

Tengo un método estático definido en una clase base, quiero anular este método en su clase secundaria, ¿es posible?¿Es posible anular un método estático en la clase derivada?

Intenté esto pero no funcionó como esperaba. Cuando creé una instancia de la clase B e invoqué su método callMe(), se invoca el método static foo() en la clase A.

public abstract class A { 
    public static void foo() { 
    System.out.println("I am base class"); 
    } 

    public void callMe() { 
    foo(); 
    } 
} 

Public class B { 
    public static void foo() { 
     System.out.println("I am child class"); 
    } 
} 
+2

No debe ser llamando a métodos estáticos desde un objeto en primer lugar, debería llamarlo desde la clase. –

Respuesta

16

Las llamadas a métodos estáticos se resuelven en tiempo de compilación (sin despacho dinámico).

class main { 
    public static void main(String args[]) { 
      A a = new B(); 
      B b = new B(); 
      a.foo(); 
      b.foo(); 
      a.callMe(); 
      b.callMe(); 
    } 
} 
abstract class A { 
    public static void foo() { 
     System.out.println("I am superclass"); 
    } 

    public void callMe() { 
     foo(); //no late binding here; always calls A.foo() 
    } 
} 

class B extends A { 
    public static void foo() { 
     System.out.println("I am subclass"); 
    } 
} 

da

I am superclass 
I am subclass 
I am superclass 
I am superclass 
+0

Cambié de opinión y escribí "sin despacho dinámico", ya que ese es el concepto general involucrado. – Artefacto

+0

Uh, no utiliza CallMe() en todos los ... – RCIX

+1

Los términos correctos son "superclase" y "subclase", no "clase base" y "clase hija". – Jesper

0

No. No es posible.

Algunas preguntas similares (no iguales) here y here.

4

En Java, las búsquedas método estático se determinan en tiempo de compilación y no puede adaptarse a las subclases que se cargan después de la compilación.

1

Solo para agregar un por qué a esto. Normalmente, cuando llamas a un método, el objeto al que pertenece el método se usa para encontrar la implementación adecuada. Obtiene la capacidad de anular un método haciendo que un objeto proporcione su propio método en lugar de usar el proporcionado por el padre.

En el caso de los métodos estáticos, no hay ningún objeto para indicar qué implementación usar. Eso significa que el compilador solo puede usar el tipo declarado para elegir la implementación del método para llamar.

0

Los métodos estáticos se resuelven en tiempo de compilación. Por lo tanto, si desea llamar al método de clase principal, debe llamar explícitamente con className o instancia como se indica a continuación.

A.foo(); 

o

A a = new A(); 
a.foo(); 
24

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

0

En una imperiosa método estático pocas palabras no es polimorfismo es "escondite método". Al anular un método estático, no tendrá acceso al método de la clase base, ya que estará oculto por la clase derivada. El uso de super() arrojará un error de tiempo de compilación ..

Cuestiones relacionadas