Kurz erklärt
Ein Objekt einer Unterklasse kann überall dort verwendet werden, wo die Oberklasse erwartet wird — beim Methodenaufruf entscheidet der tatsächliche Objekttyp zur Laufzeit, welche Implementierung läuft.
Genauer
Beispiel: eine Variable vom Typ Tier kann zur Laufzeit ein Hund-Objekt enthalten; ruft man geraeusch() auf, läuft die überschriebene Hund-Version, obwohl der Variablentyp Tier ist ("dynamic dispatch"). Das erlaubt z. B. eine Liste List<Tier> mit gemischten Unterklassen, bei der jedes Element sein eigenes Verhalten zeigt.