Let's try to look at this line the same way that the compiler would:
animal.dogMethod();
First, it needs to work out what animal
means. That's nice and easy - it's a local variable in the current method, so it doesn't need to look far.
The compile-time type of that variable is Animal
. The compiler doesn't care what the value of the variable will be at execution time - it only uses the information about the declared type.
So, that's what it uses to try to look up what dogMethod()
means within the context of animal
, i.e. with type Animal
. First it looks in Animal
, then in java.lang.Object
(the implicit superclass of Animal
) - but neither of those classes contains a declaration of dogMethod
. At that point, the compiler has to give up with an error - it can't find the method. It doesn't matter that the method is available on the execution-time type of the object that the value that animal
refers to. It has to bind it at compile-time, using only the information available at compile time.
The only decision made at execution time is which implementation of a method is used - for example, if you called animal.toString()
and the Dog
class had an override, e.g.
@Override public String toString() {
return "I'm a dog";
}
then the compiler would find the toString()
method from java.lang.Object
, so it would know that the method call was valid - but the implementation in Dog
would be used because of the execution-time type of the object.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…