Sicherlich fragt ihr euch nun “Was soll das denn?”.
Nun ja, ich fand es sehr schwer im Netz Informationen zum Thema “Substitutionsprinzip” zu finden, als ich die Übungsaufgaben der Veranstaltung “Informatik B – Objekorientiertes Programmieren in Java” von der Uni Osnabrück bearbeiten wollte, daher hier die schlussendliche Weisheit, die man zu Thema parat haben sollte, auf dass die nächste Generation von InfoBlern beim Googeln was brauchbares finden möge.
Was ist das eigentlich ?
Es geht dabei um Vererbung in der Objekt-Orientierung. Das Liskovsche Substitutionsprinzip ( Ersetzungsprinzip ) sagt aus, dass eine Unterklasse stets alle Eigenschaften der Oberklasse erfüllen und immer als Objekt der Oberklasse verwendbar sein muss. Eine Unterklasse darf Erweiterungen enthalten, nicht aber grundlegende Änderungen.
Was ist das da mit diesen Varianzen ?
Es geht hauptsächlich um die überschriebenen Methoden in Unterklassen, und wie sich dort die Argumenttypen, Rückgabetypen, sonstige Signaturerweiterungen ( z.B. Exceptions ) oder generische Klassenparameter gegenüber der Oberklasse verhalten.
Allgemein wird hier zwischen drei verschiedenen Varianzen unterschieden.
Bei den Beispielen wird davon ausgegangen, dass Student von Person erbt und Buch von Dokument.
Invarianz
Wie der Name schon sagt, es gibt keine Varianz. Die Typen sind sowohl in der Methode der Oberklasse, als auch in der überschriebenen Methode der Unterklasse gleich.
Person schreibt():Buch Student schreibt():Buch |
Kovarianz
Die Typhierarchie geht mit der Vererbungshierarchie.
Person schreibt():Dokument Student schreibt():Buch |
Kontravarianz
Die Typhierarchie ist entgegengesetzt zur Vererbungshierarchie.
Person liest(Buch) Student liest(Dokument) |
Wann erfüllen welche Varianzen nun wo das Liskovsche Substitutionsprinzip?
Eingabetypen
Auf der Eingabeseite ist das Prinzip erfüllt durch Invarianz und Kontravarianz.
Die Invarianz ist offensichtlich, wenn sowohl der Student, als auch die Person ein Buch lesen können, dann kann es kein Problem geben. Die Kontravarianz ist da dann wohl eher nicht so offensichtlich.
Wird eine Instanz einer Unterklasse einer Referenz vom Typ der Oberklasse zugewiesen, so wird die Oberklasse durch die Unterklasse substituiert. Eine typsichere Substitution erfordert, dass alles was vorher mit der Oberklasse möglich war, ebenfalls mit der Unterklasse machbar ist.
Person p = new Student(); |
Das bedeutet, dass die Unterklasse mindestens fähig sein muss, alle Eingaben, die bei der Oberklasse gemacht werden können, entgegen zu nehmen. Das ist ( außer natürlich bei Invarianz ) nur bei Kontravarianz der Fall. Ruft man die Methode liest() nun mit einem Buch auf ( p.liest(Buch) ), so kann der Student damit umgehen, da er bei Einhaltung der Kontravarianz mit sämtlichen Dokumenten klarkommt. Umgekehrt wäre das nicht der Fall.
Rückgabetyp
Im Rückgabetyp wird das Liskovsche Substitutionsprinzip bei Invarianz und Kovarianz erfüllt. Der Fall der Invarianz ist wie bei der Eingabe trivial. Wenn sowohl Student als auch Person ein Buch schreiben können, so ist das Prinzip natürlich erfüllt. Auch der Fall der Kovarianz liegt im Grunde auf der Hand. Gibt ein Person allgemein ein Dokument zurück und der Student ein Buch, so entsteht auch hier kein Problem, da man auf jedes beliebige Dokument in der Rückgabe vorbereitet ist, z.B. auch auf ein Buch.
Wie funktioniert das nun in Java ?
Eingabeseite
Auf der Eingabeseite unterstützt Java direkt nur die Invarianz. Kontravarianz würde zwar auch das Liskovsche Substitutionsprinzip erfüllen, aber die Methode hätte dann eine andere Signatur, und wäre somit nicht überschrieben, sondern überladen, und somit vom Compiler bereits anhand des Referenztypen, an dem sie aufgerufen wird, entsprechend zugeordnet.
Rückgabeseite
Auf der Rückgabeseite unterstützt Java sowohl die Invarianz als auch die Kovarianz. Sind die Rückgabetypen einer überschriebenen Mehode kovariant, so ist diese tatsächlich überschrieben. Normalerweise würde ein abweichender Rückgabetyp bei einer überschriebenen Methode zu einem Compiler-Fehler führen. Kovariante Rückgabetypen in Unterklassen bilden hier eine Ausnahme. Wenn also eine Frage nach einer Ausnahme in dem Zusammenhang auftauchen sollte, dann meinen die genau das damit.
Ich hoffe, damit sind nun alle Klarheiten beseitigt. Mich hat das Thema besonders verwirrt, aber durch das Niederschreiben ist mir das nun auch selbst endgültig bewusst geworden. Ich hoffe, alle anderen Gepeinigten können mit den Ausführungen mehr anfangen, als mit den paar fadenscheinigen Stichworten auf der Vorlesungsfolie.