This is often contrasted with static. This means "at compile time". As you can already guess, compile-time means at the time that you are compiling a program.
There's a problem with the word static. It's used in too many places. For example, static variables have nothing to do with compile-time. In this case, static means relating to the class (as opposed to the object).
To be honest, they should simply get rid of the terms dynamic and static and use runtime and compile-time. It makes for far less confusion.
This is a kind of hierarchy. It's called an inheritance hierarchy.
Suppose we declare a Human object called bob. We could say bob is a Human. We could also say bob is a Mammal (since Human is derived from Mammal). We could also say that bob is an Animal.
In fact, Java allows you to do the following:
Human bob = new Human() ; Mammal bob2 = bob ; Animal bob3 = bob ;Notice that bob, bob2, and bob3 are all object variables of different types, and all share a handle to the same Human object.
Human bob = new Human() ; Mammal bob2 = bob ; Animal bob3 = bob ;The declared type of bob is Human. The declared type of bob2 is Mammal. The declared type of bob3 is Animal.
As you can see, the declared type is static. That is, it's information we know at compile-time. After all, you're forced to write down the type of variables in a program before it's compiled.
However, the actual type of bob, bob2 and bob3 is Human.
The actual type is dynamic. This means "at runtime". While you can tell from the declaration above that bob, bob2 and bob3 is Human, in general, you can keep reassigning say bob3 to objects that have type Animal, Mammal or Human.
In particular, you can only call methods from your declared type. Thus, the declared type of bob2 is Mammal, then only Mammal methods can be used on bob2. You can't use methods that only appear in Human. You can use Animal methods, but only because Mammal inherites those methods anyway.
Suppose Animal defines method a1() and a2(), Mammal defines method b1() and b2(), and Human defines method h1() and h2().
You can only call methods a1(), a2(), b1(), and b2() on bob2 since the declared type of bob2 is Mammal.
Even though bob2 has actual type of Human, you can't call methods h1() and h2(). (Later on, we'll explain how to access those methods: it has to do with dynamic casting).
When you make the call bob2.m1(), does it call the Mammal version (i.e., does it call the method based on the declared type), or does it call the Human version which overrode the Mammal version (i.e., does it call the method based on the actual type).
Since this section is called Dynamic Dispatch, you should guess that the answer is that it bases the choice of method on the actual type, i.e., the runtime type. Thus, it picks the Human version.
Therefore, Java takes the conservative approach, and only allows method calls based on the declared type.
x = y ;You can do this assignment if the declared type of y is a descendant class of the declared type of x.
Notice I used declared types in both cases. This is why:
Mammal m ; Animal h = new Human() ; // INVALID! Declared type of h not descendant // class of declared type of m m = h ;Even though m can be assigned to a Human object (since Human is a descendant class of Animal), the compiler sees h, whose declared type is Animal.
The Java compiler assumes that h could hold an Animal object. Therefore, it doesn't permit this assignment.
Let's see what would happen if it did allow this assignment. Suppose m were assigned to h, an Animal object. If we call m.m1(), the program would crash because h has a handle to an Animal object which doesn't define m1(). m1() was defined in Mammal and doesn't appear in Animal.
Mammal m ; Human h = new Human() ; m = h ;The assignment statement is never a problem. We know that Human can handle all the methods than Mammal can. Even if h is a handle to an object from a descendant class of Human, then its methods must have at least the method that appear in Human which is a superset of the methods of Mammal.
Drawable d1 = new Rectangle() ; System.out.println( "The area is: " + d1.getArea() ) ;The declared type of d1 is Drawable. The actual type is Rectangle. It calls getArea() from Rectangle. In fact, there's no choice in this matter. Drawable is an interface, and has no method definitions to run!
When the call to d1.getArea() is made, the method run must be determined at runtime.