I am learning Java and have been playing with up and downcasting in my command prompt using the classes I defined in Eclipse. I am working with three classes that I included here, and my question is at the bottom:
public class Animal {
public static void main(String[] args) {
// TODO Auto-generated method stub
}
public void eat() {
System.out.println("Yummy");
}
public void sleep() {
System.out.println("I like sleep.");
}
}
public class Mammal extends Animal {
public static void main(String[] args) {
// TODO Auto-generated method stub
}
public void controlTemp() {
System.out.println("Temperature regulation ");
}
}
public class Lion extends Mammal {
public static void main(String[] args) {
// TODO Auto-generated method stub
}
#Override
public void sleep() {
super.sleep();
System.out.println("Especially on the grass.");
}
#Override
public void controlTemp() {
super.controlTemp();
System.out.println("I'm an endotherm.");
}
public void roar() {
System.out.println("ROARRRRR!");
}
}
Here is what I did in jshell in my cmd:
jshell> Animal a1 = new Lion();
a1 ==> Lion#4afc40bb
| created variable a1 : Animal
jshell> ((Mammal)a1).controlTemp();
Temperature regulation
I'm an endotherm.
jshell> ((Lion)a1).controlTemp();
Temperature regulation
I'm an endotherm.
My question is why does casting a1 to Mammal give me the result of the overridden controlTemp() method in my Lion class instead of the one in the Mammal class?
Because all non-static methods in java are always resolved via a thing called dynamic dispatch.
To be slightly more specific, what method signature you actually select depends on the type of the thing you invoke it on. The expression ((Mammal) a1) is of type Mammal (not because a1 is a lion; it's because anything cast to Mammal is an expression of type Mammal).
But, for a given signature, the actual method you get? That depends entirely on the runtime type of the actual object that your expression references.
At the runtime level, methods don't just have a name: Their full signature includes their parameter types, their name, and their return type.
As your #Override annotation indicates, the public void controlTemp() in your Lion class has the same name, the same argument types (namely: noa arguments), and the same return type (namely: void), and thus it overrides the void controlTemp() method in Mammal.
This gets us to the following flow:
You 'selected' the controlTemp() method as defined in Mammal, and this is compiled into your class file. In other words, during compilation, it's all about Mammal. That's what the expression's type is.
But at runtime, this method is dynamically dispatched: The actual object that your a1 ref is pointing at is checked, is found to be an instance of Lion, and the most specific version of the controlTemp method that any instance of Lion has, is the one defined in Lion. So that one gets invoked.
So how do you invoke the one from animal? not possible, except from within public class Lion extends Mammal {}, where you can use super.controlTemp() to invoke it. Anywhere else, you simply cannot do so (at least, not without raw class hackery, which is well beyond scope of the level you're at and not something anybody writing in java-the-language ever does for good reason).
Related
I'm currently doing an assignment for one of my classes, and in it, I have to give examples, using Java syntax, of static and dynamic binding.
I understand the basic concept, that static binding happens at compile time and dynamic binding happens at runtime, but I can't figure out how they actually work specifically.
I found an example of static binding online that gives this example:
public static void callEat(Animal animal) {
System.out.println("Animal is eating");
}
public static void callEat(Dog dog) {
System.out.println("Dog is eating");
}
public static void main(String args[])
{
Animal a = new Dog();
callEat(a);
}
And that this would print "animal is eating" because the call to callEat uses static binding, but I'm unsure as to why this is considered static binding.
So far none of the sources I've seen have managed to explain this in a way that I can follow.
From Javarevisited blog post:
Here are a few important differences between static and dynamic binding:
Static binding in Java occurs during compile time while dynamic binding occurs during runtime.
private, final and static methods and variables use static binding and are bonded by compiler while virtual methods are bonded during runtime based upon runtime object.
Static binding uses Type (class in Java) information for binding while dynamic binding uses object to resolve binding.
Overloaded methods are bonded using static binding while overridden methods are bonded using dynamic binding at runtime.
Here is an example which will help you to understand both static and dynamic binding in Java.
Static Binding Example in Java
public class StaticBindingTest {
public static void main(String args[]) {
Collection c = new HashSet();
StaticBindingTest et = new StaticBindingTest();
et.sort(c);
}
//overloaded method takes Collection argument
public Collection sort(Collection c) {
System.out.println("Inside Collection sort method");
return c;
}
//another overloaded method which takes HashSet argument which is sub class
public Collection sort(HashSet hs) {
System.out.println("Inside HashSet sort method");
return hs;
}
}
Output: Inside Collection sort method
Example of Dynamic Binding in Java
public class DynamicBindingTest {
public static void main(String args[]) {
Vehicle vehicle = new Car(); //here Type is vehicle but object will be Car
vehicle.start(); //Car's start called because start() is overridden method
}
}
class Vehicle {
public void start() {
System.out.println("Inside start method of Vehicle");
}
}
class Car extends Vehicle {
#Override
public void start() {
System.out.println("Inside start method of Car");
}
}
Output: Inside start method of Car
Connecting a method call to the method body is known as Binding. As Maulik said "Static binding uses Type(Class in Java) information for binding while Dynamic binding uses Object to resolve binding." So this code :
public class Animal {
void eat() {
System.out.println("animal is eating...");
}
}
class Dog extends Animal {
public static void main(String args[]) {
Animal a = new Dog();
a.eat(); // prints >> dog is eating...
}
#Override
void eat() {
System.out.println("dog is eating...");
}
}
Will produce the result: dog is eating... because it is using the object reference to find which method to use. If we change the above code to this:
class Animal {
static void eat() {
System.out.println("animal is eating...");
}
}
class Dog extends Animal {
public static void main(String args[]) {
Animal a = new Dog();
a.eat(); // prints >> animal is eating...
}
static void eat() {
System.out.println("dog is eating...");
}
}
It will produce : animal is eating... because it is a static method, so it is using Type (in this case Animal) to resolve which static method to call. Beside static methods private and final methods use the same approach.
Well in order to understand how static and dynamic binding actually works? or how they are identified by compiler and JVM?
Let's take below example where Mammal is a parent class which has a method speak() and Human class extends Mammal, overrides the speak() method and then again overloads it with speak(String language).
public class OverridingInternalExample {
private static class Mammal {
public void speak() { System.out.println("ohlllalalalalalaoaoaoa"); }
}
private static class Human extends Mammal {
#Override
public void speak() { System.out.println("Hello"); }
// Valid overload of speak
public void speak(String language) {
if (language.equals("Hindi")) System.out.println("Namaste");
else System.out.println("Hello");
}
#Override
public String toString() { return "Human Class"; }
}
// Code below contains the output and bytecode of the method calls
public static void main(String[] args) {
Mammal anyMammal = new Mammal();
anyMammal.speak(); // Output - ohlllalalalalalaoaoaoa
// 10: invokevirtual #4 // Method org/programming/mitra/exercises/OverridingInternalExample$Mammal.speak:()V
Mammal humanMammal = new Human();
humanMammal.speak(); // Output - Hello
// 23: invokevirtual #4 // Method org/programming/mitra/exercises/OverridingInternalExample$Mammal.speak:()V
Human human = new Human();
human.speak(); // Output - Hello
// 36: invokevirtual #7 // Method org/programming/mitra/exercises/OverridingInternalExample$Human.speak:()V
human.speak("Hindi"); // Output - Namaste
// 42: invokevirtual #9 // Method org/programming/mitra/exercises/OverridingInternalExample$Human.speak:(Ljava/lang/String;)V
}
}
When we compile the above code and try to look at the bytecode using javap -verbose OverridingInternalExample, we can see that compiler generates a constant table where it assigns integer codes to every method call and byte code for the program which I have extracted and included in the program itself (see the comments below every method call)
By looking at above code we can see that the bytecodes of humanMammal.speak(), human.speak() and human.speak("Hindi") are totally different (invokevirtual #4, invokevirtual #7, invokevirtual #9) because the compiler is able to differentiate between them based on the argument list and class reference. Because all of this get resolved at compile time statically that is why Method Overloading is known as Static Polymorphism or Static Binding.
But bytecode for anyMammal.speak() and humanMammal.speak() is same (invokevirtual #4) because according to compiler both methods are called on Mammal reference.
So now the question comes if both method calls have same bytecode then how does JVM know which method to call?
Well, the answer is hidden in the bytecode itself and it is invokevirtual instruction set. JVM uses the invokevirtual instruction to invoke Java equivalent of the C++ virtual methods. In C++ if we want to override one method in another class we need to declare it as virtual, But in Java, all methods are virtual by default because we can override every method in the child class (except private, final and static methods).
In Java, every reference variable holds two hidden pointers
A pointer to a table which again holds methods of the object and a pointer to the Class object. e.g. [speak(), speak(String) Class object]
A pointer to the memory allocated on the heap for that object’s data e.g. values of instance variables.
So all object references indirectly hold a reference to a table which holds all the method references of that object. Java has borrowed this concept from C++ and this table is known as virtual table (vtable).
A vtable is an array like structure which holds virtual method names and their references on array indices. JVM creates only one vtable per class when it loads the class into memory.
So whenever JVM encounter with a invokevirtual instruction set, it checks the vtable of that class for the method reference and invokes the specific method which in our case is the method from a object not the reference.
Because all of this get resolved at runtime only and at runtime JVM gets to know which method to invoke, that is why Method Overriding is known as Dynamic Polymorphism or simply Polymorphism or Dynamic Binding.
You can read it more details on my article How Does JVM Handle Method Overloading and Overriding Internally.
The compiler only knows that the type of "a" is Animal; this happens at compile time, because of which it is called static binding (Method overloading). But if it is dynamic binding then it would call the Dog class method. Here is an example of dynamic binding.
public class DynamicBindingTest {
public static void main(String args[]) {
Animal a= new Dog(); //here Type is Animal but object will be Dog
a.eat(); //Dog's eat called because eat() is overridden method
}
}
class Animal {
public void eat() {
System.out.println("Inside eat method of Animal");
}
}
class Dog extends Animal {
#Override
public void eat() {
System.out.println("Inside eat method of Dog");
}
}
Output:
Inside eat method of Dog
There are three major differences between static and dynamic binding while designing the compilers and how variables and procedures are transferred to the runtime environment.
These differences are as follows:
Static Binding: In static binding three following problems are discussed:
Definition of a procedure
Declaration of a name(variable, etc.)
Scope of the declaration
Dynamic Binding: Three problems that come across in the dynamic binding are as following:
Activation of a procedure
Binding of a name
Lifetime of a binding
With the static method in the parent and child class: Static Binding
public class test1 {
public static void main(String args[]) {
parent pc = new child();
pc.start();
}
}
class parent {
static public void start() {
System.out.println("Inside start method of parent");
}
}
class child extends parent {
static public void start() {
System.out.println("Inside start method of child");
}
}
// Output => Inside start method of parent
Dynamic Binding :
public class test1 {
public static void main(String args[]) {
parent pc = new child();
pc.start();
}
}
class parent {
public void start() {
System.out.println("Inside start method of parent");
}
}
class child extends parent {
public void start() {
System.out.println("Inside start method of child");
}
}
// Output => Inside start method of child
All answers here are correct but i want to add something which is missing.
when you are overriding a static method, it looks like we are overriding it but actually it is not method overriding. Instead it is called method hiding. Static methods cannot be overridden in Java.
Look at below example:
class Animal {
static void eat() {
System.out.println("animal is eating...");
}
}
class Dog extends Animal {
public static void main(String args[]) {
Animal a = new Dog();
a.eat(); // prints >> animal is eating...
}
static void eat() {
System.out.println("dog is eating...");
}
}
In dynamic binding, method is called depending on the type of reference and not the type of object that the reference variable is holding
Here static bindinghappens because method hiding is not a dynamic polymorphism.
If you remove static keyword in front of eat() and make it a non static method then it will show you dynamic polymorphism and not method-hiding.
i found the below link to support my answer:
https://youtu.be/tNgZpn7AeP0
In the case of the static binding type of object determined at the compile-time whereas in
the dynamic binding type of the object is determined at the runtime.
class Dainamic{
void run2(){
System.out.println("dainamic_binding");
}
}
public class StaticDainamicBinding extends Dainamic {
void run(){
System.out.println("static_binding");
}
#Override
void run2() {
super.run2();
}
public static void main(String[] args) {
StaticDainamicBinding st_vs_dai = new StaticDainamicBinding();
st_vs_dai.run();
st_vs_dai.run2();
}
}
Because the compiler knows the binding at compile time. If you invoke a method on an interface, for example, then the compiler can't know and the binding is resolved at runtime because the actual object having a method invoked on it could possible be one of several. Therefore that is runtime or dynamic binding.
Your invocation is bound to the Animal class at compile time because you've specified the type. If you passed that variable into another method somewhere else, noone would know (apart from you because you wrote it) what actual class it would be. The only clue is the declared type of Animal.
This question already has answers here:
What is method hiding in Java? Even the JavaDoc explanation is confusing
(8 answers)
When is method hiding practically used?
(5 answers)
Closed 4 years ago.
The question has been put up to discuss around the term hiding which is associated with static methods in java.
Whenever a static method with the same signature is defined in the parent and the child class, the child class method is said to have hidden the method in the parent class. My question is around the usage of hiding, as we know static methods would be accessed by the class name or if we try to create a reference (which is a bad practice), method would be called based on the reference type. So how does hiding comes into picture, take example of below code:
public class Animal {
public static void testClassMethod() {
System.out.println("The static method in Animal");
}
}
public class Cat extends Animal {
public static void testClassMethod() {
System.out.println("The static method in Cat");
}
public static void main(String[] args) {
Cat myCat = new Cat();
Animal myAnimal = myCat;
Animal.testClassMethod(); // prints The static method in Animal
}
}
Can someone please explain how child method has hidden the parent method here? (parent method is being called using parent reference, so how does hiding comes into picture)
This demonstrates exactly why it's a bad practice to intend to hide a static method. The method is chosen statically, at compile time, without any consideration for the actual instance type.
I suppose the take home phrase should be "hiding is not overriding... and don't do it", to mean that Java doesn't even look at the object/instance (only looking at the declared type):
Cat myCat = new Cat();
Animal myAnimal = myCat;
Animal.testClassMethod();
myAnimal.testClassMethod(); //bad to do, but you can see it uses the declared "Animal" class
Cat.testClassMethod(); //Uses method in Cat
myCat.testClassMethod(); //Uses method in Cat
((Animal) null).testClassMethod(); //Uses Animal method, doesn't look at instance
((Cat) null).testClassMethod(); //Uses Cat method, doesn't look at instance
Now the interesting part: what if you remove the method from Cat?
All of these invocations will still work, using the Animal method, which means that:
It's a very bad practice to hide static methods
It's equally bad to use class instances to invoke static methods, because in the case of hidden methods, it's easy to be misled...
To answer the question: hiding is illustrated with Cat.testClassMethod() or myCat.testClassMethod(), which invokes the static method based on the declared type. When there's no testClassMethod() in Cat, Java calls the parent's.
How has the child method hidden the parent method here?
As you said, by defining a static method with the identical signature.
How does hiding comes into the picture?
Cat.testClassMethod();
Some may expect the invocation of the parent method here (by analogy with polymorphism). But the idea of hiding by class methods is different:
If a class C declares or inherits a static method m, then m is said to hide any method m', where the signature of m is a subsignature (§8.4.2) of the signature of m', in the superclasses and superinterfaces of C that would otherwise be accessible (§6.6) to code in C.
...
A hidden method can be accessed by using a qualified name or by using a method invocation expression (§15.12) that contains the keyword super or a cast to a superclass type.
...
class Super {
static String greeting() { return "Goodnight"; }
String name() { return "Richard"; }
}
class Sub extends Super {
static String greeting() { return "Hello"; }
String name() { return "Dick"; }
}
class Test {
public static void main(String[] args) {
Super s = new Sub();
System.out.println(s.greeting() + ", " + s.name()); // Goodnight, Dick
}
}
JLS 10 - 8.4.8.2. Hiding (by Class Methods)
This example is perfect to show the difference between overriding and hiding. At the same time, it is a bad practice demonstration - calling static methods on an instance.
I will try to make it clear by providing another example.
Since public static methods are inherited, the following snippet
class Animal {
public static void testClassMethod() {
System.out.println("The static method in Animal");
}
}
class Cat extends Animal {
public static void main(String[] args) {
// Cat: I don't have own method, probably I inherited it from the parent.
// O, yes. I can call it.
Cat.testClassMethod();
}
}
prints
The static method in Animal
Now we're going to add testClassMethod to Cat.
class Animal {
public static void testClassMethod() {
System.out.println("The static method in Animal");
}
}
class Cat extends Animal {
public static void testClassMethod() {
System.out.println("The static method in Cat");
}
public static void main(String[] args) {
// Cat: I have two version of the method: mine and the inherited one.
// The caller specified my class name, so he wanted my version.
// I will call my method hiding the parent method.
Cat.testClassMethod();
// If he wanted Animal's version, he would write
Animal.testClassMethod();
// or (DON'T DO THIS)
((Animal)new Cat()).testClassMethod();
}
}
All final, static and private methods and variables use static binding and are bonded by compiler. Static binding uses Type information for binding (in this case Animal).
So, in your case myAnimal.testClassMethod(); will print the static method in Animal because declared type is Animal.
static methods don't take part in dynamic binding (polymorphism).
static methods aren't overritten, static methods are hidden by the subclass.
someone who calls Cat.testClassMethod() might expect the behaviour of Animal.testClassMethod()
So Cat.testClassMethod() is hiding Animal.testClassMethod()
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.
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 :
JLS - Is the Chosen Method Appropriate?
On the same topic :
Java Static confusion
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
Some of the known Overriding "PITFALLS"
static methods cannot be overridden
private methods cannot be overridden
This explains the output.
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.
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.
While coding, I got an interesting doubt about polymorphism and I couldn't understand a solution for this.
public class Animal {
public void getLegs() {
SOP("4 legs");
}
}
public class Kangaroo extends Animal {
public void getLegs() {
SOP("2 legs");
}
public static void main(String[] args) {
Animal a = new Kangaroo(); // without changing this how can I get Animal getLegs
SOP(a.getLegs()); // Important Line
}
}
Now If I want to call the getLegs method of Animal, how do I? Is it possible? Is it still polymorphism?
Yes, it is the most basic form of demonstrating polymorphisim.
Basically you are dealing with an Animal named a. When you call a.getLegs() your code doesn't bind to the implementation of getLegs() in Animal, rather it binds to the lowest sub-class implementation, getLegs() in Kangraoo().
If the Animal has an implementation, it is said to be hidden by the subclass implementation. If Animal has no implementation, then it is not possible to construct stand-alone classes of Animal as they lack implementations for all of the required methods, and under such a circumstance, Animal is said to be an abstract class (one that cannot be constructed directly, but only can be constructed by it's sub classes).
If you really want to call your method for Animal, and you can employ a static method, you can use hiding instead of overriding.
It works as follows: for static methods only, the called method is the one related to the declared type, not the object instance. In other words, it follows the class because the method is a class method, not an instance method.
An example, adapted from this page:
public class Animal {
public static void testClassMethod() {
System.out.println("The class" + " method in Animal.");
}
public void testInstanceMethod() {
System.out.println("The instance " + " method in Animal.");
}
}
public class Kangaroo extends Animal {
public static void testClassMethod() {
System.out.println("The class method" + " in Kangaroo.");
}
public void testInstanceMethod() {
System.out.println("The instance method" + " in Kangaroo.");
}
public static void main(String[] args) {
Kangaroo myRoo = new Kangaroo();
Animal myAnimal = myRoo;
myRoo.testInstanceMethod();
myAnimal.testInstanceMethod();
Kangaroo.testClassMethod();
Animal.testClassMethod();
}
}
The result will be (pay attention to the 3rd and 4th lines, as opposed to the 1st and 2nd):
The instance method in Kangaroo.
The instance method in Kangaroo.
The class method in Kangaroo.
The class method in Animal.
In Java it's not possible to access Animal's implementation. It will always return Kangaroo's version.
(Note in C# it is possible by tagging the overriding method with "new", but it's a fairly specialised use case).
Accessing what appears to be an Animal but getting the behaviour specified by Kangaroo is exactly what polymorphism is - the ability for a child object to be substituted wherever its parent is expected.
In general you wouldn't want to have the calling code know about the inheritance hierarchy because this would tightly couple your code together. If you genuinely need to access Animal's implementation of this method it suggests your design is probably wrong.
The spirit of Polymorphism is to execute different code decided at runtime. To make it more clear, I'll modify your code a bit.
public class Animal {
public void getLegs(){
SOP('4 legs');
}
}
public class Kangaroo extends Animal{
public void getLegs(){
SOP('2 legs');
}
public static void main(String[] args){
Animal a = new Kangaroo(); //without changing this how can I get Animal getLegs
Kangaroo kng= new Kangaroo ();
Animal an = new Animal();
SOP(a.getLegs()); // Kangaroo's version is called
SOP(kng.getLegs()); //Again, Kangaroo's version is called
SOP(an.getLegs()); //Animal version is called
}
}
and Yes, as all say you can't call Animal from your line Animal a = new Kangaroo();..as none will want to do it. Rather he will directly write. Animal a = new Animal();..
So finally it is the object not referance which decides which method will be called
Now If I want to call the getLegs method of Animal, how do I? Is it possible?
If you want to access the overridden method - which contradicts polymorphism - you can use reflection. Get the getLegs method from Animal's class, and then invoke it on your Kangaroo object. However, this is a hack, and not something you'd do in a regular program.
SOP( Animal.class.getMethod("getLegs").invoke(a) );
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.
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 :
JLS - Is the Chosen Method Appropriate?
On the same topic :
Java Static confusion
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
Some of the known Overriding "PITFALLS"
static methods cannot be overridden
private methods cannot be overridden
This explains the output.
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.
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.