(Dynamische) Polymorphie
Unter (dynamischer) Polymorphie (griechisch für „Vielgestaltigkeit") versteht man, dass eine Referenzvariable zur Laufzeit Referenzen auf Objekte unterschiedlicher Klassen halten kann und dadurch unterschiedliche Methodenimplementierungen aufgerufen werden. Man unterscheidet dabei zwischen dem statischen Datentyp (zur Designzeit festgelegt) und dem dynamischen Datentyp (zur Laufzeit zugewiesen). Der statische Typ bestimmt, welche Methoden aufrufbar sind; der dynamische Typ bestimmt, welche Implementierung tatsächlich ausgeführt wird. Die Typumwandlung von der Unterklasse zur Oberklasse nennt man Upcast, die Rückumwandlung 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, memoryInGb);
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 cpu1 = new Cpu(3.5, 8);
Cpu cpu2 = new Cpu(4.7, 8);
Notebook notebook1 = new Notebook("Mein Office Laptop", cpu1, 16, 14);
Notebook notebook2 = new Notebook("Mein Gaming Laptop", cpu2, 32, 16);
Computer computer;
ArrayList<Computer> computers = new ArrayList<>();
computer = notebook1; // Upcast
computers.add(computer);
computer = notebook2; // Upcast
computers.add(computer);
for (Computer c : computers) {
System.out.println(c.getSpecification()); // Polymorphie
Notebook notebook = (Notebook) c; // Downcast
System.out.println(notebook.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 lässt sich zur Laufzeit prüfen, ob eine
Objektreferenz mit einer bestimmten Klasse zuweisungskompatibel ist. Seit Java
16 ermöglicht der Mustervergleich (Pattern Matching) bei instanceof das
direkte Binden in eine neue Variable ohne expliziten Downcast.
public class MainClass {
public static void main(String[] args) {
...
for (Computer c : computers) {
// bis Java 16: expliziter Downcast erforderlich
if (c instanceof Notebook) {
Notebook notebook = (Notebook) c;
System.out.println(notebook.getScreenSizeInInches());
}
// seit Java 16: Pattern Matching
if (c instanceof Notebook notebook) {
System.out.println(notebook.getScreenSizeInInches());
}
}
...
}
}