tags:

views:

110

answers:

5

Sample 1:

 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();
    }
 }

Output is:

 Gurrr! Gurrr! Moo!

Sample 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();
    }
 }

Output:

 Gurrr! Moo! Moo!

I just don't understand why making saySomething non-static causes the second call to saySomething invoke the Cow version instead of the Animal version. My understanding was that Gurrr! Moo! Moo! would be the output in either case.

+7  A: 

When you call saySomething() on an animal, the actual type of the animal doesn't count because saySomething() is static.

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

is the same as

Animal.saySomething();

A JLS example :

When a target reference is computed and then discarded because the invocation mode is static, the reference is not examined to see whether it is null:

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();
   }

}

which prints:
Mount Monadnock
Here favorite returns null, yet no NullPointerException is thrown.


Resources :

On the same topic :

Colin Hebert
I have never understood why Java allows invocation of a static method through an object reference. It isn't necessary, and it leads to confusion like this.
erickson
Agreed. C++ lets you do it too. My guess would be it just makes things easier for the compiler writer to allow this kind of access.
Brent Nash
Well, I tried to defend that here : http://stackoverflow.com/questions/3610309/java-static-confusion/
Colin Hebert
+3  A: 

You cannot override static methods with the same signature in subclasses, just hide them.

For class methods, the runtime system invokes the method defined in the compile-time type of the reference on which the method is called. For instance methods, the runtime system invokes the method defined in the runtime type of the reference on which the method is called.

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

The MYYN
+3  A: 

Some of the known Overriding "PITFALLS"

  • static methods cannot be overridden
  • private methods cannot be overridden

This explains the output.

andreas
+1  A: 

Static methods are tied to the "Class", not the "Instance" of the object. Since you are referring to an "Animal" and calling the static method saySomething(). It will always make the call to "Animal" unless you are referring to a Cow.

ScArcher2
+1  A: 

static methods are bound to their class at compile time and cannot be used polymorphically. When you declare a "static" method on Animal, it is forever bound to the Animal class and cannot be overridden. Static methods are bound to the Class object, not an instance of the Class.

Regular methods are bound at runtime and so the JVM can look at your call to "saySomething" and attempt to determine if you're passing around a subclass of Animal and if so, has it overridden the saySomething() method. Regular methods are bound to an instance of an object, not to the Class itself.

This is also why you could never do this:

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

Since "static" means "bound at compile time", it never makes sense for something to be static and abstract.

Brent Nash