Innanzitutto c'è un concetto teorico che è sbagliato, ovvero la gerarchia che hai fatto. Potrebbe ad esempio venirti in mente di fare una ulteriore classe es. Point3D che estende Point2D. Sbagliato concettualmente! Un Gatto è un caso particolare di Animale, una Automobile è un caso particolare di Veicolo. Ma un punto 3D NON è un caso particolare di punto 2D. Idem tra 1D e 2D.
Dovunque è lecito assegnare o passare un Point1D, puoi tecnicamente passare un Point2D. Ma non avrebbe senso.

Infatti non ha senso es.:

double d = unPoint1D.distance(unPoint2D);

Stop, fine della questione.


E per tornare alla questione del binding dinamico, basta tenere a mente due cose:
- il compilatore sceglie solo la "firma" del metodo (eventualmente tra quelle in overload) basandosi solo sul tipo "statico" del reference. Ad esempio in base al tipo della variabile su cui si sta invocando il metodo.
- a runtime la implementazione del metodo che viene eseguito è quella dell'oggetto realmente istanziato.

Se vuoi approfondire questi aspetti, innanzitutto scegli un design più appropriato.