Динамическая отправка - это когда реализация метода выбирается на основе фактического, а не объявленного типа. Java не поддерживает динамическую диспетчеризацию, кроме как через отражение. Это статически типизированная полиморфная отправка.
Если у вас загружена одна реализация, JVM применит моморфную оптимизацию (получая очень быстрые вызовы), которая будет отменена, когда JVM увидит, что вторая реализация передана тому же коду.
Возможно, вы слышали о новом байт-коде invokedynamic, который реализует динамическую диспетчеризацию в JVM, но он предназначен для использования другими языками JVM, и программы Java не будут использовать его, кроме случаев, когда выполняется генерация байт-кода.
[Edit] Вот простой пример:
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