Stromzähler im Mehrfamilienhaus
AFB I–IIEine Hausverwaltung erfasst die Stromzähler eines Mehrfamilienhauses mit einer Java-Anwendung. Jeder Zähler hat eine Zählernummer und einen Zählerstand in kWh. Mit erhoehen wird ein positiver Verbrauch aufaddiert. Ein Auszubildender testet die Klasse mit dem abgebildeten Programmausschnitt. In der Variablen alt möchte er sich den alten Zählerstand „merken“, in z2 den Zähler „zum Ausprobieren“.
- - nummer: Zeichenkette
- - stand: Ganzzahl
- c Zaehler(nummer: Zeichenkette, stand: Ganzzahl)
- + getNummer(): Zeichenkette
- + getStand(): Ganzzahl
- + erhoehen(kwh: Ganzzahl)
int alt = 4200;
Zaehler z1 = new Zaehler("Z-01", 4200);
Zaehler z2 = z1;
Zaehler z3 = new Zaehler("Z-01", 4200);
int neu = alt;
neu = neu + 150;
z2.erhoehen(150);
z3.erhoehen(30);
erhoehen addiert kwh zum Stand, falls kwh > 0 gilt.- Geben Sie nach Ausführung des Ausschnitts die Werte von
alt,neu,z1.getStand()undz3.getStand()sowie die Ergebnisse der Vergleichez1 == z2undz1 == z3an. - Stellen Sie den Speicherzustand nach Ausführung des Ausschnitts dar: alle fünf Variablen mit ihrem Inhalt und alle erzeugten Objekte als Objektkarten.
- Erklären Sie, warum das „Merken“ mit
altgelingt, das „Ausprobieren“ mitz2aber den Zählerz1verändert, obwohl in beiden Fällen nur eine Zuweisung mit=verwendet wird.
Hinweise
Hinweis zu Aufgabe a)
new steht – so viele Zähler-Objekte gibt es. Verfolge dann, welche Variable auf welches Objekt verweist.Angeben heißt: nur die Werte, keine Begründung.Hinweis zu Aufgabe b)
Hinweis zu Aufgabe c)
alt, was steht in z1? Die Zuweisung kopiert immer den Inhalt der Variablen – überlege, was dieser Inhalt jeweils ist.Erwartungshorizont
Erwartungshorizont zu Aufgabe a)
alt = 4200, neu = 4350, z1.getStand() liefert 4350, z3.getStand() liefert 4230, z1 == z2 ergibt true, z1 == z3 ergibt false.
Erwartungshorizont zu Aufgabe b)
| Variable | Inhalt |
|---|---|
alt | 4200 |
neu | 4350 |
z1 | Referenz auf Objekt A |
z2 | Referenz auf Objekt A |
z3 | Referenz auf Objekt B |
- nummer = "Z-01"
- stand = 4350
- nummer = "Z-01"
- stand = 4230
Es gibt genau zwei Objekte (zweimal new). z1 und z2 verweisen auf dasselbe Objekt A (Alias), z3 auf das eigene Objekt B. „A“ und „B“ sind nur Bezeichner für die Skizze; eine Darstellung mit Pfeilen von den Variablen zu den Karten ist gleichwertig.
Erwartungshorizont zu Aufgabe c)
alt ist eine Variable vom primitiven Typ int; sie speichert den Wert 4200 selbst. int neu = alt; kopiert diesen Wert, danach sind alt und neu unabhängig – die Änderung von neu lässt alt unverändert.
z1 ist eine Variable vom Objekttyp Zaehler; sie speichert nur eine Referenz auf das Objekt. Zaehler z2 = z1; kopiert diese Referenz, es entsteht kein neues Objekt. Beide Variablen verweisen auf dasselbe Objekt, daher wirkt z2.erhoehen(150) auf den Zähler, den auch z1 bezeichnet. Für eine unabhängige Kopie wäre ein neues Objekt mit new nötig, wie bei z3.
Doppelte Termine im Schulkalender
AFB II–IIIDie Schülervertretung entwickelt einen digitalen Schulkalender. Ein Termin besteht aus einem Titel, dem Tag im Schuljahr (1 bis 200) und der Anfangsstunde. Die Klasse Kalender stellt Hilfsmethoden bereit, die Termine als Parameter erhalten. Die Titel werden später aus einer Datei eingelesen; zwei gleich lautende Titel sind dann in der Regel zwei verschiedene String-Objekte. Im Testprogramm wird dieser Fall mit new String("Elternabend") nachgebildet.
Beim Testen fällt auf, dass die Methode istDoppelt einen doppelt eingetragenen Elternabend nicht erkennt. Außerdem ist unklar, ob absagen einen Termin tatsächlich löscht.
- - titel: Zeichenkette
- - tag: Ganzzahl
- - stunde: Ganzzahl
- c Termin(titel: Zeichenkette, tag: Ganzzahl, stunde: Ganzzahl)
- + getTitel(): Zeichenkette
- + getTag(): Ganzzahl
- + getStunde(): Ganzzahl
- + verschieben(tage: Ganzzahl)
public class Kalender {
public void verlegen(Termin t, int tage) {
t.verschieben(tage);
}
public void verlegenTag(int tag, int tage) {
tag = tag + tage;
}
public void absagen(Termin t) {
t = null;
}
public boolean kollidiert(Termin a, Termin b) {
return a.getTag() == b.getTag() && a.getStunde() == b.getStunde();
}
public boolean istDoppelt(Termin a, Termin b) {
return a.getTitel() == b.getTitel() && kollidiert(a, b);
}
}
Kalender k = new Kalender();
Termin a = new Termin(new String("Elternabend"), 40, 19);
Termin b = new Termin(new String("Elternabend"), 40, 19);
Termin c = a;
System.out.println(k.istDoppelt(a, b)); // (1)
System.out.println(k.istDoppelt(a, c)); // (2)
int tag = a.getTag();
k.verlegenTag(tag, 7);
k.verlegen(c, 2);
k.absagen(b);
System.out.println(tag + " " + a.getTag() + " " + b.getTag()); // (3)
System.out.println(k.kollidiert(a, b)); // (4)
verschieben(tage) addiert tage zum Attribut tag.- Analysieren Sie das Testprogramm, indem Sie die Ausgaben (1) bis (4) ermitteln und jeweils mit der Art der Parameterübergabe bzw. des Vergleichs begründen.
- Überprüfen Sie die Aussage einer Mitschülerin: „Die Methode
absagensetzt den Termin aufnull. Ein anschließender Aufrufb.getTag()führt deshalb zu einem Fehler.“ - Implementieren Sie eine korrigierte Methode
istDoppelt, die auch fürnull-Parameterfalseliefert, sowie eine Methodewiederholen(t: Termin, tage: Ganzzahl): Termin, die einen neuen Termin mit gleichem Titel und gleicher Stunde liefert, dertageTage später liegt. Der übergebene Termin darf dabei nicht verändert werden. - Beurteilen Sie, ob zum Verlegen eines Termins die vorhandene Methode
verlegen(verändert das übergebene Objekt) oder ein Vorgehen wie beiwiederholen(liefert ein neues Objekt) günstiger ist, wenn derselbe Termin gleichzeitig im Kalender der Klasse 11a und im Kalender der Lehrkraft eingetragen ist.
Hinweise
Hinweis zu Aufgabe a)
int-Wert übergeben oder eine Referenz?Hinweis zu Aufgabe b)
t ist eine eigene lokale Variable der Methode. Welche Variable wird durch t = null; verändert – und welche nicht?Hinweis zu Aufgabe c)
equals. Prüfe null, bevor du eine Methode aufrufst. Für ein unabhängiges Objekt brauchst du new.Hinweis zu Aufgabe d)
Erwartungshorizont
Erwartungshorizont zu Aufgabe a)
(1) false: a und b sind zwei Objekte mit zwei verschiedenen String-Objekten „Elternabend“. == vergleicht bei Zeichenketten die Referenzen, nicht den Inhalt – der erste Teil der Bedingung ist falsch.
(2) true: c verweist auf dasselbe Objekt wie a; beide liefern dieselbe String-Referenz, Tag und Stunde stimmen überein.
(3) 40 42 40: verlegenTag erhält eine Kopie des Wertes 40; die Änderung des Parameters wirkt nicht auf die Variable tag. verlegen(c, 2) erhält eine Kopie der Referenz auf das Objekt, das auch a bezeichnet; verschieben ändert dieses Objekt, daher liefert a.getTag() 42. absagen(b) setzt nur den Parameter auf null, b verweist weiter auf seinen Termin mit Tag 40.
(4) false: Tag 42 und Tag 40 stimmen nicht überein.
Erwartungshorizont zu Aufgabe b)
Die Aussage ist falsch. Beim Aufruf k.absagen(b) wird die Referenz aus b in den Parameter t kopiert. t = null; ändert nur diese lokale Kopie; die Variable b im Testprogramm verweist weiterhin auf das Termin-Objekt. b.getTag() liefert daher 40, wie Ausgabe (3) bestätigt. Auch das Objekt selbst wird nicht verändert. Eine Methode kann über einen Parameter zwar den Zustand des Objekts ändern (wie verlegen), aber nicht, worauf die Variable des Aufrufers verweist.
Erwartungshorizont zu Aufgabe c)
public boolean istDoppelt(Termin a, Termin b) {
if (a == null || b == null) {
return false;
}
return a.getTitel().equals(b.getTitel()) && kollidiert(a, b);
}
public Termin wiederholen(Termin t, int tage) {
if (t == null) {
return null;
}
return new Termin(t.getTitel(), t.getTag() + tage, t.getStunde());
}
Wesentlich: equals statt ==; null-Prüfung vor dem ersten Methodenaufruf (Kurzschlussauswertung von ||); in wiederholen ein neues Objekt mit new, ohne t.verschieben aufzurufen. Beispiel: k.wiederholen(a, 7) liefert einen Termin mit Tag 49, a behält Tag 42. Die Rückgabe von null bei fehlendem Termin ist eine sinnvolle, aber nicht zwingende Festlegung.
Erwartungshorizont zu Aufgabe d)
Kriterien: Konsistenz der Daten an allen Stellen, an denen der Termin bekannt ist; Vermeidung unerwünschter Nebeneffekte; Aufwand und Speicherbedarf.
Veränderndes Verlegen: Verweisen beide Kalender auf dasselbe Termin-Objekt (Alias), sieht nach verlegen sofort jeder Kalender den neuen Tag. Die Daten bleiben ohne Zusatzaufwand konsistent, und es entsteht kein weiteres Objekt. Nachteil: Wer den Termin nur „für sich“ verschieben will, verändert unbemerkt auch die anderen Kalender.
Neues Objekt: Der alte Termin bleibt unverändert, es gibt keine Nebeneffekte. Dafür müssten alle Kalender einzeln die alte Referenz durch die neue ersetzen; wird einer vergessen, stehen dort widersprüchliche Termine.
Mögliches Urteil: Für einen gemeinsamen Termin (Klasse und Lehrkraft sollen denselben Zeitpunkt haben) ist das verändernde verlegen günstiger, weil die Alias-Wirkung hier genau erwünscht ist. Das Erzeugen eines neuen Objekts passt dagegen für Wiederholungstermine, bei denen das Original erhalten bleiben muss. Ein anderes Urteil ist bei schlüssiger Begründung ebenfalls möglich.
