2010-09-09 13 views
7

Muestra 1:¿Por qué estos dos ejemplos de código producen salidas diferentes?

class Animal { 
    public static void saySomething() { System.out.print(" Gurrr!"); 
    } 
} 
class Cow extends Animal { 
    public static void saySomething() { 
    System.out.print(" Moo!"); 
    } 
    public static void main(String [] args) { 
     Animal [] animals = {new Animal(), new Cow()}; 
     for(Animal a : animals) { 
      a.saySomething(); 
     } 
     new Cow().saySomething(); 
    } 
} 

de salida es:

Gurrr! Gurrr! Moo! 

Muestra 2:

class Animal { 
    public void saySomething() { System.out.print(" Gurrr!"); 
    } 
} 
class Cow extends Animal { 
    public void saySomething() { 
    System.out.print(" Moo!"); 
    } 
    public static void main(String [] args) { 
     Animal [] animals = {new Animal(), new Cow()}; 
     for(Animal a : animals) { 
      a.saySomething(); 
     } 
     new Cow().saySomething(); 
    } 
} 

Salida:

Gurrr! Moo! Moo! 

Simplemente no entiendo por qué hacer saySomething no-stat ic provoca la segunda llamada para decir Algo invocar la versión Vaca en lugar de la versión Animal. Mi entendimiento fue que Gurrr! Moo! Moo! sería la salida en cualquier caso.

+0

"La especificación del lenguaje Java dice que sí" es realmente todo lo que hay que hacer. Por qué se le permite llamar a un método estático desde una referencia de instancia como esa en primer lugar es la rareza real. Pero ya hay al menos un enorme hilo wiki de la comunidad sobre eso :) – Affe

Respuesta

1

los métodos estáticos están vinculados a su clase en tiempo de compilación y no se pueden usar polimórficamente. Cuando declaras un método "estático" en Animal, siempre está vinculado a la clase Animal y no puede anularse. Los métodos estáticos están vinculados al objeto Class, no a una instancia de la clase.

Los métodos regulares están vinculados en el tiempo de ejecución y la JVM puede ver su llamada a "saySomething" e intentar determinar si está pasando por una subclase de Animal y, de ser así, ha anulado el método saySomething(). Los métodos regulares están vinculados a una instancia de un objeto, no a la clase misma.

Esta es la razón por la que nunca podría hacer esto:

class Animal 
{ 
    public abstract static void saySomething(); 
} 

Dado que los medios "estáticos" "con destino en tiempo de compilación", que nunca tiene sentido para que algo sea estático y abstracto.

7

Cuando llama al saySomething() en un animal, el tipo real del animal no cuenta porque saySomething() es estático.

Animal cow = new Cow(); 
cow.saySomething(); 

es la misma que

Animal.saySomething(); 

Un ejemplo JLS:

Cuando se calcula una referencia de destino y luego descartado porque la modalidad de invocación es estática, la referencia es no examinado para ver si es nulo:

class Test { 
    static void mountain() { 
     System.out.println("Monadnock"); 
    } 
    static Test favorite(){ 
     System.out.print("Mount "); 
     return null; 
    } 
    public static void main(String[] args) { 
     favorite().mountain(); 
    } 

}

que imprime:
Monte Monadnock
Aquí favorito vuelve nula, sin embargo, no se lanza NullPointerException.


Recursos:

Sobre el mismo tema:

+1

Nunca he entendido por qué Java permite la invocación de un método estático a través de una referencia de objeto. No es necesario, y genera confusión como esta. – erickson

+0

de acuerdo. C++ te permite hacerlo también. Supongo que simplemente facilita las cosas al escritor de compilación para permitir este tipo de acceso. –

+0

Bueno, traté de defender eso aquí: http://stackoverflow.com/questions/3610309/java-static-confusion/ –

3

No se puede anulación métodos estáticos con la misma firma en subclases, simplemente ocultar ellos.

Para métodos de clase, el sistema de tiempo de ejecución invoca el método definido en el tipo de tiempo de compilación de la referencia en el que se llama al método. Por ejemplo, los métodos, el sistema de ejecución invoca el método definido en el tipo de tiempo de ejecución de la referencia en la que se llama al método.

http://life.csu.edu.au/java-tut/java/javaOO/override.html

3

Algunas de las "trampas" Sustitución conocidos

  • métodos estáticos no se pueden sustituir
  • métodos privados no se pueden sustituir

Esto explica la salida.

1

Los métodos estáticos están vinculados a la "Clase", no a la "Instancia" del objeto. Dado que te estás refiriendo a un "Animal" y llamando al método estático saySomething(). Siempre hará la llamada a "Animal" a menos que te refieras a una Vaca.

Cuestiones relacionadas