Objektorientierung: Klassen, Objekte und Polymorphie
Du unterscheidest Klassen und Objekte, sicherst gültige Zustände und bestimmst bei überschriebenen Methoden die passende Ausführung.
Kurz gesagt
Objektorientierung bündelt Daten und Verhalten in Objekten, deren Bauplan eine Klasse ist. Kapselung ermöglicht kontrollierte Änderungen; Vererbung und Polymorphie verbinden gemeinsame Merkmale mit eigenen Methodenumsetzungen.
Bei der Objektorientierung fasst du zusammengehörige Daten und Aktionen zusammen. Java ist die hier verwendete Programmiersprache. Die erfundenen Klassenmodelle beschreiben Klassen und ihr Verhalten vereinfacht; sie sind keine vollständigen ausführbaren Programme. Einzelne Aufrufe stehen in Java-Schreibweise.
Deine Lernziele
Eine Klasse ist ein Bauplan für gleichartige Objekte. Sie legt fest, welche Attribute und Methoden diese Objekte besitzen. Ein Objekt ist ein einzelnes Exemplar einer Klasse. Dafür verwendet man auch das Wort Instanz.
Ein Attribut ist ein benannter Speicherplatz für Daten eines Objekts. Die aktuellen Attributwerte bilden seinen Zustand. Eine Methode ist ein benannter Programmteil mit Anweisungen für das Verhalten. Sie kann zum Beispiel Attributwerte lesen oder ändern. Eine Instanzmethode gehört zum Verhalten eines einzelnen Objekts. Alle hier betrachteten Methoden sind Instanzmethoden.
Eine Variable ist ein benannter Speicherplatz im Programm. Variablen wie notizA enthalten hier einen Verweis, also einen Bezug auf ein Objekt. Bei notizA.anzeigen() gibt notizA das angesprochene Objekt an; hinter dem Punkt steht der Methodenname. Die Klammern enthalten die übergebenen Eingaben. Leere Klammern bedeuten, dass keine Eingabe übergeben wird. Verschiedene Objekte derselben Klasse können unterschiedliche Attributwerte haben.
Zustand und Verhalten
Der Zustand besteht aus den aktuellen Attributwerten eines Objekts. Sein Verhalten wird durch Methoden beschrieben, die diese Werte lesen oder verändern können.
Beispiel: Zwei Notizen nach demselben Bauplan
- 1Die Klasse Notiz legt das Attribut inhalt und die Methode anzeigen() fest. Diese Methode liefert den gespeicherten Inhalt.
- 2Die Objekte A und B sind verschiedene Notizen: A enthält „Idee“, B enthält „Termin“.
- 3Die Variable notizA verweist auf A. notizA.anzeigen() liefert „Idee“.
- 4Die Variable notizB verweist auf B. notizB.anzeigen() liefert „Termin“.
Teste dich
Ein Konstruktor ist ein besonderer Bestandteil einer Klasse. Er heißt wie die Klasse und initialisiert ein neues Objekt: Er setzt dessen Anfangswerte. Bei dem Java-Ausdruck new Kartenbox(3) wird Speicher für ein neues Objekt reserviert und der Konstruktor Kartenbox mit der Eingabe 3 aufgerufen. Der gesamte Ausdruck liefert einen Verweis auf das erzeugte Objekt.
Eine Gültigkeitsregel legt fest, welche Zustände erlaubt sind. Unsere erfundene Kartenbox darf eine ganze Anzahl von 0 bis 8 Karten enthalten. Ihr Konstruktor übernimmt einen Startwert nur dann, wenn er diese Regel erfüllt. Andernfalls wird die Erzeugung abgebrochen; es wird kein fertig erzeugtes Kartenbox-Objekt zurückgegeben.
Kapselung bedeutet hier: Der gespeicherte Zustand ist vor direktem Zugriff von außen geschützt. Dafür trägt das Attribut anzahl das Java-Schlüsselwort „private“. In diesem Klassenmodell greifen die Methoden der Klasse Kartenbox auf das Attribut zu. Nach der Erzeugung kann anzahl ausschließlich durch setzeAnzahl geändert werden. Diese Methode übernimmt ganze Zahlen von 0 bis 8. Andere Eingaben weist sie ab und lässt den bisherigen Wert unverändert; sie kürzt Werte nicht auf eine Grenze.
Der Zugriffsschutz prüft selbst keine Zahlen. Damit der Zustand gültig bleibt, muss die Initialisierung einen gültigen Anfangszustand herstellen. Außerdem muss jede erlaubte Änderung die Gültigkeitsregel erhalten. Ein ungeprüfter Konstruktor oder eine ungeprüfte Änderung könnte trotz „private“ einen ungültigen Zustand erzeugen.
Initialisierung
Initialisierung ist das Setzen der Anfangswerte eines neuen Objekts. Der Konstruktor muss dabei die Gültigkeitsregel des Klassenmodells einhalten.
Beispiel: Eine Kartenbox anlegen und ändern
- 1new Kartenbox(2) erzeugt ein Objekt mit anzahl 2. Der Startwert liegt zwischen 0 und 8.
- 2setzeAnzahl(7) setzt bei diesem Objekt anzahl auf 7.
- 3setzeAnzahl(10) wird abgewiesen. Der gespeicherte Wert bleibt 7.
Merke: „private“ schützt vor direktem Zugriff von außen. Gültige Zustände erfordern zusätzlich eine passende Initialisierung und erlaubte Änderungen, die die Gültigkeitsregel erhalten.
Teste dich
Bei der Vererbung bildet eine Unterklasse eine speziellere Art einer Oberklasse. Sie kann deren zugängliche Methoden übernehmen und eigene Merkmale ergänzen. Eine Unterklasse kann außerdem eine geerbte Instanzmethode überschreiben, also deren Umsetzung durch eine eigene ersetzen.
Im erfundenen Modell besitzt die Klasse Leuchte das private Attribut helligkeit. Erlaubt sind ganze Zahlen von 0 bis 10. Der Konstruktor setzt den Anfangswert 0. Die Methode setzeHelligkeit übernimmt gültige Eingaben und lässt den Wert bei ungültigen Eingaben unverändert. Das ist die einzige erlaubte Änderung der Helligkeit. Diese Regeln verwirklichen Kapselung mit einer Prüfung der Werte.
Blinkleuchte und Dauerleuchte sind Unterklassen von Leuchte. Beide übernehmen die zugängliche Methode setzeHelligkeit. Das private Attribut wird weiterhin durch die Methoden aus Leuchte verwaltet; die Unterklassen erhalten dadurch keinen direkten Zugriff darauf. Leuchte besitzt außerdem die Methode signal(), die „Licht“ liefert. Blinkleuchte überschreibt sie mit dem Ergebnis „Blinken“, Dauerleuchte mit „Leuchten“.
Ein Typ legt fest, welche Art von Werten eine Variable aufnehmen darf. Ein Klassentyp wie Leuchte erlaubt hier Verweise auf Leuchte-Objekte und auf Objekte ihrer Unterklassen. Polymorphie bedeutet in diesem Beispiel: Eine Variable vom Typ Leuchte kann auf unterschiedliche Leuchtenarten verweisen. Der gleiche Aufruf signal() führt dann die passende Umsetzung des jeweiligen Objekts aus.
Überschreiben
In diesen Modellen überschreibt eine Unterklasse eine geerbte Instanzmethode ohne Eingaben, indem sie unter demselben Namen eine eigene Umsetzung festlegt. Die überschriebenen Methoden liefern jeweils Text.
| Prinzip | Im Leuchtenmodell |
|---|---|
| Kapselung | Die Helligkeit ist privat; Änderungen erfolgen über die prüfende Methode. |
| Vererbung | Blinkleuchte und Dauerleuchte übernehmen setzeHelligkeit aus Leuchte. |
| Polymorphie | signal() liefert je nach tatsächlichem Objekt „Blinken“ oder „Leuchten“. |
Teste dich
Der deklarierte Typ einer Variablen ist der Typ, der im Programm für diese Variable festgelegt wurde. Er ist vom tatsächlichen Objekt zu unterscheiden, auf das die Variable gerade verweist. Eine Variable vom deklarierten Typ Anzeiger kann zum Beispiel auf ein Objekt der Unterklasse Punktanzeiger verweisen.
Wir betrachten Java-Aufrufe von Instanzmethoden, die bereits im deklarierten Typ vorhanden sind. Bei einer überschriebenen Methode bestimmt die tatsächliche Klasse des angesprochenen Objekts die ausgeführte Umsetzung. Dieses Auswählen während der Programmausführung heißt dynamische Bindung. Der deklarierte Variablentyp entscheidet hier also nicht darüber, welche überschriebene Umsetzung läuft.
Für die gezeigten Klassen gehst du so vor: Bestimme das Objekt, auf das die Variable beim Aufruf verweist. Prüfe dann, ob dessen Klasse die Methode überschreibt. Falls ja, läuft diese Umsetzung. Falls die Unterklasse die Methode unverändert erbt, läuft die geerbte Umsetzung. Bei einer neuen Zuweisung kann die Variable auf ein anderes Objekt verweisen. Ihr deklarierter Typ bleibt dabei unverändert; der nächste Aufruf richtet sich nach dem nun angesprochenen Objekt.
Dynamische Bindung
Bei den hier betrachteten überschriebenen Java-Instanzmethoden wird die passende Umsetzung während der Ausführung anhand des tatsächlichen Objekts ausgewählt.
Beispiel: Zwei Aufrufe an unterschiedlichen Anzeigern
- 1Die Klasse Anzeiger besitzt die Methode meldung(), die „Bereit“ liefert.
- 2Punktanzeiger ist eine Unterklasse und überschreibt meldung() mit dem Ergebnis „Punkte“.
- 3Rahmenanzeiger ist ebenfalls eine Unterklasse von Anzeiger. Sie erbt meldung() unverändert.
- 4Die Variable a hat den deklarierten Typ Anzeiger und verweist zunächst auf einen Punktanzeiger. a.meldung() liefert „Punkte“.
- 5Danach verweist a auf einen Rahmenanzeiger. a.meldung() liefert nun „Bereit“ aus der geerbten Umsetzung.
Teste dich
Alles auf einen Blick
Objektorientierung
Die Klasse beschreibt den Bauplan; ein Objekt ist ein einzelnes Exemplar davon.
Attributwerte bilden den Zustand; Methoden beschreiben das Verhalten.
Bei new wird Speicher reserviert und ein Konstruktor zur Initialisierung aufgerufen.
Geschützter Zugriff ermöglicht kontrollierte Änderungen. Gültigkeit erfordert eine passende Initialisierung und Änderungen, die die Regel erhalten.
Unterklassen können Methoden übernehmen und überschreiben. Über einen gemeinsamen Klassentyp lassen sich unterschiedliche Objektarten ansprechen.
Bei den gezeigten überschriebenen Instanzmethoden bestimmt das tatsächliche Objekt die ausgeführte Umsetzung.
Den Methodenaufruf an einem Pinsel bestimmen
- 1Im erfundenen Modell besitzt die Klasse Werkzeug die Instanzmethode beschreiben(). Sie liefert „Werkzeug bereit“.
- 2Die Unterklasse Pinsel überschreibt beschreiben() und liefert „Pinsel bereit“.
- 3Die Variable w hat den deklarierten Typ Werkzeug und verweist auf ein erzeugtes Pinsel-Objekt.
- 4Für w.beschreiben() bestimmen wir zuerst die tatsächliche Klasse des angesprochenen Objekts: Pinsel.
- 5Pinsel überschreibt die Methode. Deshalb läuft die Umsetzung aus Pinsel und liefert „Pinsel bereit“.
Fehler finden
Fehler in Zeile 4Der deklarierte Variablentyp wurde fälschlich zur Auswahl der Umsetzung benutzt. Richtig: s.farbe() liefert „Rot“, weil das angesprochene Objekt zur Klasse RoterStein gehört und diese die Instanzmethode überschreibt.
Lückentext
Der gemeinsame Bauplan für mehrere gleichartige Objekte ist eine . Eine erfundene Steuerung erlaubt die ganzzahligen Stufen 0 bis 5. Sie steht auf 3. Ihre Methode übernimmt gültige Eingaben und weist ungültige ohne Änderung ab. Nach der Eingabe 8 beträgt die gespeicherte Stufe . Die Klasse Drucker besitzt die Instanzmethode status(). Fotodrucker überschreibt sie mit dem Ergebnis „Foto“. Eine Variable vom Typ Drucker verweist auf ein Fotodrucker-Objekt. Beim Aufruf von status() an diesem Objekt läuft die Umsetzung aus .