Objektorientierte Programmierung OOP
KE4 Vererbung; Begriffe, Beispiele und Definitionen
KE4 Vererbung; Begriffe, Beispiele und Definitionen
Kartei Details
Karten | 94 |
---|---|
Sprache | Deutsch |
Kategorie | Informatik |
Stufe | Universität |
Erstellt / Aktualisiert | 28.02.2013 / 18.05.2022 |
Weblink |
https://card2brain.ch/box/objektorientierte_programmierung_oop6
|
Einbinden |
<iframe src="https://card2brain.ch/box/objektorientierte_programmierung_oop6/embed" width="780" height="150" scrolling="no" frameborder="0"></iframe>
|
Beispiel: Verderbliche Waren in der Artikelhierarchie
Betrachten wir noch einmal die verschiedenen Artikelgruppen eines Blumenladens. Es liegt nahe, zunächst zwischen Pflanzen und Zubehör zu unterscheiden. Pflanzen können weiter in Topfpflanzen, Schnittblumen, Trockenblumen usw. aufgeteilt werden, Zubehör lässt sich beispielsweise in Gefäße, Pflegemittel, Schmuck usw. auffächern. Eine solche Hierarchie ist sinnvoll gewählt, weil durch Spezialisierung die relevanten Eingenschaften konkreter Artikel präzise abgebildet werden können. Nun kann es aber Eigenschaften geben, die an mehreren Stellen der Hierarchie relevant sind, jedoch nicht durchgehend in einem einzelnen Zweig auftreten. Als Beispiel betrachten wir den Sachverhalt, dass gewisse Waren verderblich sind und deshalb bis zu einem festgelegten Zeitpunkt verkauft sein sollen, während andere Waren fast beliebig lange im Lagerbestand verbleiben können. Beliebig lange haltbar sind Trockenblumen, Gefäße und Schmuck, während Topfpflanzen, Schnittblumen und Pflegemittel nur begrenzt haltbar sind. Um einen Lagerbestand Artikel[] bestand; nach verderblichen Waren abfragen zu können, benötigen wir zweierlei:
• Wir müssen erkennen können, welche Artikel begrenzt haltbar sind.
• Wir wollen das Haltbarkeitsdatum dieser Artikel auf einheitliche Weise erfragen können.
Zu diesem Zweck definieren wir eine Schnittstelle BegrenztHaltbar mit einer Methode liefereHaltbarkeitsdatum(). Klassen, die verderbliche Waren repräsentieren, implementieren die Schnittstelle BegrenztHaltbar und damit die Methode liefereHaltbarkeitsdatum(). Der Lagerbestand kann sodann wie folgt abgefragt werden:
for (Artikel artikel : bestand) {
if (artikel instanceof BegrenztHaltbar) {
// ...
// verwende
// ((BegrenztHaltbar) artikel).lieferHaltbarkeitsdatum()
}
}
Die Abbildung zeigt die Artikelhierarchie mit der Schnittstelle BegrenztHaltbar. Beachten Sie, dass beliebig viele Klassen und Zweige der Artikelhierarchie die Schnittstelle implementieren können, während benachbarte Klassen und Zweige davon unberührt bleiben.
Bemerkung: Mehrfachvererbung und Vererbungskonflikte
In Java tritt Mehrfachvererbung nur im Zusammenhang mit Schnittstellen auf. Von Schnittstellen erbt eine Klasse weder Exemplarvariablen noch Methodenimplementierungen. Andere Programmiersprachen wie Common Lisp oder C++ kennen Mehrfachvererbung auch unter Klassen, was zur Folge haben kann, dass eine Unterklasse mehrere Exemplarvariablen a des gleichen Typs t oder mehrere unterschiedlich implementierte Methoden m() mit der gleichen Signatur von verschiedenen Oberklassen
erbt. Wir nennen dies einen Vererbungskonflikt, weil in solchen Fällen unklar ist, auf welche Definition des Attributs sich ein Zugriff auf a bezieht oder welche Implementierung bei einem Aufruf von m() gemeint ist. Um solche Vererbungskonflikte zu vermeiden, gelten in Programmiersprachen mit Mehrfachvererbung entweder feste Regeln zur Auflösung von Vererbungskonflikten - etwa durch die Vorgabe einer Erbreihenfolge - oder ein Verbot von Vererbungskonflikten. Falls in Java eine Klasse mehrere Schnittstellen implementiert, die Methoden mit gleicher Signatur definieren, so entsteht kein Vererbungskonflikt, denn es erfolgt nur eine einzige Methodenimplementierung in der Klasse selbst. Treten Attribute gleichen Namens in verschiedenen Schnittstellen auf, die von einer Java-Klasse implementiert werden sollen, so müssen sie innerhalb der Klasse mit ihren qualifizierten Namen angesprochen werden, anderenfalls weist der Java- Übersetzer das Programm zurück [JLS: § 9.3.2.1]. Da es sich bei in Schnittstellen definierten Attributen immer um Klassenattribute handelt, ist ihr qualifizierter Name Schnittstellenname.Attributname.Bemerkung: Unterschied zwischen String-Objekten und StringBuilder
Der Unterschied zwischen den beiden Klassen besteht darin, dass String-Objekte Zeichenketten als Konstanten behandeln, während StringBuilder-Objekte veränderliche Zeichenketten verwalten.
Eine Folge von Zeichen, die in Anführungsstrichen eingeschlossen sind, wie z. B. "Der höchste Berg Javas ist der Vulkan Semeru." erzeugt in Java automatisch ein Objekt der Klasse String, dessen Wert mit der Zeichenfolge übereinstimmt. Ein auf diese Weise erzeugtes String-Objekt wird String-Literal genannt. [JLS: § 3.10.5]
Aufgabe: Wie können in Java String und Verkettungen erzeugt werden?
String nachname = "Müller";
String vorname = new String("Heinz");
char[] letters = {’H’, ’a’, ’g’, ’e’, ’n’}; String city = new
String(letters); "Java-" + "Kaffee"
Begriff: Konkatenation
int glueckszahl;
...
System.out.println("Ihre persönliche Glückszahl lautet " + glueckszahl + ".");
Wenn glueckszahl den Wert 17 aufweist, erscheint die Ausgabe:
Ihre persönliche Glückszahl lautet 17.
Bemerkung: Automatische Umwandlung in eine Zeichenkette
Wird ein String-Objekt mit dem Verkettungsoperator mit einem Objektverweis verknüpft, so wird automatisch an diesem Objekt die toString()- Methode aufgerufen und so eine passende Zeichenkettenrepräsentation erzeugt. [JLS: § 15.18.1.1]
Aufgabe: Nennen Sie einige Methoden aus der Klasse String
int laenge = vorname.length(); // liefert 5
int ePosition = vorname.indexOf(’e’); // liefert 1
int inPosition = vorname.indexOf("in"); // liefert 2
char viertesZeichen = vorname.charAt(3); // liefert ’n’
if (vorname.indexOf(’o’) == -1) {
System.out.println("In " + vorname + " kommt kein ’o’
vor.");}
boolean eiKommtVor = vorname.contains("ei");
String vollerName = vorname.concat(nachname);
String neuerName = vorname.replace(’z’, ’o’);
String ausschnitt = vorname.substring(1, 4) // ergibt "ein"
String allesklein = vorname.toLowerCase() // ergibt "heinz"
String allesgross = vorname.toUpperCase() // ergibt "HEINZ"
Bedeutung: Strings vergleichen
Neben Methoden zur Untersuchung der Zeichenketten enthält die Klasse String auch Methoden, um Zeichenketten miteinander zu vergleichen. Dabei fordern wir jeweils ein String-Objekt auf, sich mit einem anderen String-Objekt zu vergleichen. Seien
String s = "neben";
String t = "einander";
String u = "nebeneinander";
String w = s + t;
Die Methode equals() liefert true, falls zwei Zeichenketten lexikalisch gleich sind, ansonsten false:
boolean istGleich;
istGleich = s.equals(t); // liefert false
istGleich = u.equals(s + t); // liefert true
istGleich = u.equals(w); // liefert true
Die Methode equals() ist uns als Methode der Klasse Object bereits begegnet. Auch die Klasse String ist eine Subklasse von Object; durch Überschreiben der equals()-Methode definiert sie die Gleichheit unter String-Objekten um.
Bedeutung: compareTo() Methode
Mit der Methode compareTo() erhalten wir ein differenzierteres Ergebnis. Sie liefert eine Ganzzahl, wobei drei Fälle auftreten können:
• Das Ergebnis 0 bedeutet, dass die beiden Zeichenketten lexikalisch gleich sind (und entspricht somit dem Fall, dass equals() true liefert).
• Eine negative Ganzzahl bedeutet, dass die Zeichenketten des StringObjekts, dessen compareTo-Methode aufgerufen wurde, alphabetisch vor der Zeichenkette des Parameters steht.
• Eine positive Ganzzahl signalisiert die umgekehrte Reihenfolge.
int vergleich;
vergleich = u.compareTo(w); // liefert 0
vergleich = t.compareTo(s); // liefert -9
vergleich = s.compareTo(t); // liefert 9
Bemerkung: Vergleichen von Strings
Gelegentlich werden Ihnen Vergleiche der folgenden Art begegnen:
if (u == w) { ... }
u und w sind die Namen von String-Objekten und stellen somit Referenzen auf diese Objekte dar. Der Vergleichsoperator == prüft, ob u und w auf dasselbe Objekt verweisen. Das Ergebnis dieses Vergleichs ist hier false - unabhängig davon, dass u.equals(w) true ergibt.
In gewissen Fällen kann ein Vergleich von String-Objekten mit dem Vergleichsoperator == auch zu überraschenden Ergebnissen führen:
boolean erstaunlich = (s == "neben"); // liefert true
Dieser Effekt ist dadurch zu erklären, dass die Laufzeitumgebung mit einer internen Optimierung arbeitet und versucht, die Aufbewahrung mehrerer gleicher Zeichenketten im Speicher zu vermeiden. In diesem Fall hat sie für "neben" gar nicht erst ein neues String-Objekt erzeugt, sondern lediglich eine interne Referenz angelegt, die auf das bereits im Speicher existierende String-Objekt mit der gleichen Zeichenkette "neben" verweist.
Von der Verwendung des Vergleichsoperators == zum lexikalischen Vergleich wird abgeraten. Ob die Laufzeitumgebung interne Referenzen oder „wahrhaftige“ String-Objekte anlegt, hängt von verschiedenen (nicht immer überschaubaren) Faktoren ab.
Aufgaben: Nennen Sie einige Methode der Klasse StringBuilder
StringBuilder littleBuilder = new StringBuilder();
StringBuilder bigBuilder = new StringBuilder(1000);
StringBuilder sammelBuilder = new StringBuilder("Ein Anfang");
sammelBuilder.append(", aber jetzt geht es weiter");
sammelBuilder.insert(30, " ein wenig");
sammelBuilder.delete(12, 17);
sammelBuilder.insert(3, "etwas");
StringBuilder vorname = new StringBuilder("Heinz");
StringBuilder vollerName = vorname.append("Müller");
Die Zeichenkette eines StringBuilder-Objekts kann ebenso wie diejenige eines String-Objekts mit der folgenden Anweisung ausgegeben werden: System.out.println(sammelBuilder);