Dynamic dispatch is when a method implementation is picked based on the actual and not the declared type. Java does not support dynamic dispatch, except through reflection. This is statically typed polymorphic dispatch.
If you have a single implementation loaded, the JVM will apply momomorphic optimization (yielding very fast calls) which will be undone when the JVM sees a second implementation passed to the same code.
You might have heard about the new 'invokedynamic' bytecode, which implements dynamic dispatch in the JVM, but it is intended to be used by other JVM languages and Java programs will not use it except when doing bytecode generation.
[Edit] Here is a simple example:
Collection<Integer> c = new ArrayList<Integer>(Arrays.asList(2, 1, 0));
c.remove(2); // Collection.remove(E element) or List.remove(int idx)?
assert c.equals(Arrays.asList(1, 0)); // passes in case of static dispatch
assert c.equals(Arrays.asList(2, 1)); // fails - would pass in case of dynamic dispatch