What is dynamic method dispatch in Java, and how does the JVM decide which implementation to run?
Dynamic method dispatch is the rule that a call to an instance method is resolved at run time, based on the actual type of the object the reference points at, rather than on the type the reference was declared as. It is what makes the phrase "program to an interface, not an implementation" actually work.
Mechanically, every object carries a pointer to its class's method table. When you invoke an instance method, the JVM looks up the entry for that method in the runtime class of the receiver — not in the class the compiler saw — and calls it. If the runtime class has an override, that override runs. This is also known as late binding, and it is the mechanism behind polymorphism.
The distinction that causes the most confusion is between the static type and the runtime type. The static type is the type in the declaration, and it decides which methods you are allowed to call and which overload applies. The runtime type is the class of the actual object, and it decides which implementation runs. So if a variable is declared as Animal but holds a Dog, you can only call methods that Animal declares, and the Dog's override of those methods is what runs.
Dispatch applies to instance methods only. A static method is resolved by the compiler from the static type, and a private method cannot be overridden at all, so neither is subject to dispatch.