(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 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
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 notebook = (Notebook) c; // Downcast
System.out.println(notebook.getScreenSizeInInches());
}
/* seit Java 16 */
if (c instanceof Notebook notebook) { // Downcast
System.out.println(notebook.getScreenSizeInInches());
}
}
...
}
}