(Dynamische) Polymorphie
Unter (dynamischer) Polymorphie (griechisch für Vielgestaltigkeit) versteht man, dass eine Referenzvariable zur Laufzeit durch Typumwandlung Referenzen auf Objekte unterschiedlicher Klassen besitzen kann und dass dadurch unterschiedliche Methodenimplementierungen aufgerufen werden können. Man spricht in diesem Zusammenhang auch vom statischen Datentyp einer Referenzvariablen (der zur Designzeit festgelegt wird) und vom dynamischen Datentyp einer Referenzvariablen (der zur Laufzeit zugewiesen wird). Der statische Typ legt fest, welche Methoden aufgerufen werden können, der dynamische, welche Methodenimplementierung aufgerufen wird. Die Typumwandlung von der abgeleiteten Unterklasse zur Oberklasse bezeichnet man als Upcast, die Rückumwandlung als Downcast.
- Oberklasse
- Unterklasse
- Startklasse
public class Computer {
...
public ArrayList<String> getSpecification() {
ArrayList<String> specification = new ArrayList<>();
specification.add("description: " + description);
specification.add("cpu: " + cpu);
specification.add("memoryInGB: " + memoryInGB);
return specification;
}
...
}
public class Notebook extends Computer {
...
public Notebook(String description, CPU cpu, int memoryInGB, double screenSizeInInches) {
super(description, cpu, mainMemoryInGB);
this.screenSizeInInches = screenSizeInInches;
}
public double getScreenSizeInInches() {
return screenSizeInInches;
}
@Override
public ArrayList<String> getSpecification() {
ArrayList<String> specification = super.getSpecification();
specification.add("screenSizeInInches: " + screenSizeInInches);
return specification;
}
...
}
public class MainClass {
public static void main(String[] args) {
CPU myCpu1 = new CPU(3.5, 8);
CPU myCpu2 = new CPU(4.7, 8);
Notebook myNotebook1 = new Notebook("Mein Office Laptop", myCpu1, 16, 14);
Notebook myNotebook2 = new Notebook("Mein Gaming Laptop", myCpu2, 32, 16);
Computer myComputer;
ArrayList<Computer> computers = new ArrayList<>();
myComputer = myNotebook1; // Upcast
computers.add(myComputer);
myComputer = myNotebook2; // Upcast
computers.add(myComputer);
for(Computer c : computers) {
System.out.println(c.getSpecification()); // Polymorphie
Notebook myNotebook = (Notebook) c; // Downcast
System.out.println(myNotebook.getScreenSizeInInches());
}
}
}
Im Gegensatz zum Upcast muss bei einem Downcast der Typ explizit angegeben
werden. Der Downcast einer nicht zuweisungskompatiblen Referenz führt zu einer
ClassCastException
.
Der instanceof-Operator
Mit dem Operator instanceof
kann zur Laufzeit geprüft werden, ob eine
Objektreferenz zuweisungskompatibel zu einer Klasse ist. Eine Objektreferenz ist
dann zuweisungskompatibel zu einer Klasse, wenn die Klasse des referenzierten
Objektes in einer Vererbungsbeziehung zur Klasse steht. Seit Java 16 ermöglicht
der Mustervergleich bei instanceof
das Vermeiden notwendiger Typumwandlungen
und sorgt gleichzeitig für eine sicherere Programmierung.
public class MainClass {
public static void main(String[] args) {
...
for(Computer c : computers) {
/* bis Java 16 */
if (c instanceof Notebook) {
Notebook myNotebook = (Notebook) c; // Downcast
System.out.println(myNotebook.getScreenSizeInInches());
}
/* seit Java 16 */
if (c instanceof Notebook myNotebook) { // Downcast
System.out.println(myNotebook.getScreenSizeInInches());
}
}
...
}
}