Kasse für die Klassenfahrt nach Berlin
AFB I–IIFür die Klassenfahrt eines Jahrgangs verwaltet die Kassenwartin die Einzahlungen mit einem Java-Programm. Jede angemeldete Person wird durch ein Objekt der Klasse Teilnehmer dargestellt. Material 1 zeigt einen ersten Test, Material 2 die Klasse Klassenfahrt, die die Anmeldungen in einer Reihung verwaltet. Freie Plätze enthalten null.
- - name: Zeichenkette
- - bezahlt: Ganzzahl
- c Teilnehmer(name: Zeichenkette, bezahlt: Ganzzahl)
- + getName(): Zeichenkette
- + getBezahlt(): Ganzzahl
- + einzahlen(betrag: Ganzzahl)
Teilnehmer[] gruppe = new Teilnehmer[5];
gruppe[0] = new Teilnehmer("Mia", 180);
gruppe[1] = new Teilnehmer("Ben", 120);
gruppe[3] = new Teilnehmer("Ayla", 180);
gruppe[4] = gruppe[1];
gruppe[4].einzahlen(60);
int summe = 0;
for (int i = 0; i < gruppe.length; i++) {
if (gruppe[i] != null) {
summe = summe + gruppe[i].getBezahlt();
}
}
einzahlen erhöht bezahlt um einen positiven Betrag.public class Klassenfahrt {
private Teilnehmer[] teilnehmer;
private int preis;
public Klassenfahrt(int plaetze, int preis) {
teilnehmer = new Teilnehmer[plaetze];
this.preis = preis;
}
public boolean anmelden(Teilnehmer t) {
for (int i = 0; i < teilnehmer.length; i++) {
if (teilnehmer[i] == null) {
teilnehmer[i] = t;
return true;
}
}
return false;
}
}
preis ist der Fahrtpreis pro Person in Euro.- Bestimmen Sie für Material 1 die Anzahl der erzeugten Teilnehmer-Objekte, den Wert von
gruppe[1].getBezahlt()und den Wert vonsummenach dem Durchlauf. - Erläutern Sie, was die Anweisung
new Teilnehmer[5]erzeugt und welche Folge es hätte, wenn in der Schleife aus Material 1 die Abfragegruppe[i] != nullfehlte. - Erweitern Sie die Klasse
Klassenfahrtum die MethodegetOffen(): Ganzzahl, die den insgesamt noch fehlenden Betrag aller Angemeldeten liefert (Überzahlungen werden nicht verrechnet), und um die Methodesuchen(name: Zeichenkette): Teilnehmer, die die erste Person mit diesem Namen liefert odernull, falls es keine gibt.
Hinweise
Hinweis zu Aufgabe a)
new Teilnehmer("Mia", 180) – nicht die mit eckigen. Was steht nach gruppe[4] = gruppe[1]; in Platz 4?Hinweis zu Aufgabe b)
Hinweis zu Aufgabe c)
null. Namen vergleichst du mit equals; sobald du fündig bist, kannst du mit return abbrechen.Erwartungshorizont
Erwartungshorizont zu Aufgabe a)
Es gibt 3 Teilnehmer-Objekte (Mia, Ben, Ayla); new Teilnehmer[5] erzeugt nur die Reihung. gruppe[4] verweist auf dasselbe Objekt wie gruppe[1], daher erhöht gruppe[4].einzahlen(60) Bens Betrag: gruppe[1].getBezahlt() liefert 180.
Summe: Platz 0: 180, Platz 1: 180, Platz 2: null (übersprungen), Platz 3: 180, Platz 4: 180 (erneut Ben). summe = 720. Bens Einzahlung wird doppelt gezählt, weil zwei Plätze auf dasselbe Objekt verweisen – tatsächlich eingezahlt sind nur 540 Euro.
Erwartungshorizont zu Aufgabe b)
new Teilnehmer[5] erzeugt ein Reihungsobjekt mit fünf Plätzen für Referenzen auf Teilnehmer-Objekte. Alle Plätze sind mit null vorbelegt; es wird kein einziges Teilnehmer-Objekt erzeugt. Jedes Objekt muss einzeln mit einem Konstruktoraufruf wie new Teilnehmer("Mia", 180) erzeugt und einem Platz zugewiesen werden.
Ohne die Abfrage würde bei i = 2 der Aufruf gruppe[2].getBezahlt() ausgeführt. Da gruppe[2] den Wert null hat, gibt es kein Objekt, das die Methode ausführen könnte: Es tritt eine NullPointerException auf, das Programm bricht ab, und die Plätze 3 und 4 werden nicht mehr summiert.
Erwartungshorizont zu Aufgabe c)
public int getOffen() {
int offen = 0;
for (int i = 0; i < teilnehmer.length; i++) {
if (teilnehmer[i] != null && teilnehmer[i].getBezahlt() < preis) {
offen = offen + (preis - teilnehmer[i].getBezahlt());
}
}
return offen;
}
public Teilnehmer suchen(String name) {
for (int i = 0; i < teilnehmer.length; i++) {
if (teilnehmer[i] != null && teilnehmer[i].getName().equals(name)) {
return teilnehmer[i];
}
}
return null;
}
Beispiel: Preis 240 Euro, angemeldet Mia (240), Ben (180), Ayla (0): getOffen() liefert 0 + 60 + 240 = 300. Bewertungsrelevant: null-Prüfung vor dem Getter-Aufruf (Kurzschlussauswertung), equals statt ==, return null erst nach der Schleife.
Automatische Bewässerung im Schulgewächshaus
AFB II–IIIDie Garten-AG steuert die Bewässerung des Schulgewächshauses mit Feuchtigkeitssensoren. Das Gewächshaus hat nummerierte Beete; jedes Beet ist leer oder enthält eine Pflanze. Die Klasse Gewaechshaus speichert die Beete in einer Reihung, deren Index der Beetnummer entspricht.
einsetzen(platz, p) setzt die Pflanze p in das Beet platz und liefert true, falls das Beet existiert und leer ist; sonst bleibt alles unverändert und es wird false geliefert. entfernen(platz) leert ein existierendes Beet. Die Methode giessen(menge) der Klasse Pflanze erhöht die Feuchte um menge Prozentpunkte, höchstens auf 100.
- - beete: Reihung vom Typ Pflanze
- c Gewaechshaus(anzahl: Ganzzahl)
- + einsetzen(platz: Ganzzahl, p: Pflanze): Wahrheitswert
- + entfernen(platz: Ganzzahl)
- + hoechste(): Ganzzahl
- - art: Zeichenkette
- - feuchte: Ganzzahl
- - hoehe: Ganzzahl
- c Pflanze(art: Zeichenkette, feuchte: Ganzzahl, hoehe: Ganzzahl)
- + getArt(): Zeichenkette
- + getFeuchte(): Ganzzahl
- + getHoehe(): Ganzzahl
- + giessen(menge: Ganzzahl)
Gewaechshaus g = new Gewaechshaus(6);
Pflanze t = new Pflanze("Tomate", 35, 80);
g.einsetzen(0, t);
g.einsetzen(2, new Pflanze("Basilikum", 55, 20));
g.einsetzen(2, new Pflanze("Paprika", 30, 45));
g.einsetzen(5, new Pflanze("Gurke", 25, 120));
g.einsetzen(6, new Pflanze("Minze", 60, 15));
g.einsetzen(3, t);
g.entfernen(0);
public int hoechste() {
int max = 0;
int platz = 0;
for (int i = 0; i < beete.length; i++) {
if (beete[i].getHoehe() > max) {
max = beete[i].getHoehe();
platz = i;
}
}
return platz;
}
hoechste soll die Nummer des Beetes mit der höchsten Pflanze liefern.- Stellen Sie die Belegung der Reihung
beetenach Ausführung der Testfolge dar, geben Sie die Rückgabewerte der sechseinsetzen-Aufrufe an und stellen Sie die vorhandenen Pflanzen-Objekte als Objektkarten dar. - Implementieren Sie die Methoden
trockenste(): Pflanze, die die Pflanze mit der geringsten Feuchte liefert (nullbei leerem Gewächshaus), undbewaessern(grenze: Ganzzahl, menge: Ganzzahl): Ganzzahl, die jede Pflanze mit einer Feuchte untergrenzemitmengegießt und die Anzahl der gegossenen Pflanzen liefert. Geben Sie das Ergebnis vong.bewaessern(40, 20)für den Zustand aus a) an. - Analysieren Sie die Methode
hoechsteaus Material 3 hinsichtlich ihres Verhaltens bei leeren Beeten, bei einem vollständig leeren Gewächshaus und bei gleich hohen Pflanzen, und geben Sie eine verbesserte Fassung an. - Vergleichen Sie die gewählte Speicherung (Index = Beetnummer, Lücken mit
null) mit einer Alternative, bei der alle Pflanzen lückenlos am Anfang der Reihung stehen und ein Attributanzahldie Zahl der Pflanzen angibt, und entscheiden Sie begründet, welche Variante für das Gewächshaus geeigneter ist.
Hinweise
Hinweis zu Aufgabe a)
Hinweis zu Aufgabe b)
trockenste die bisher trockenste Pflanze als Referenz, beginnend mit null – dann brauchst du keinen „Startwert“ für die Feuchte. Gegossen wird über die Methode der Pflanze.Hinweis zu Aufgabe c)
hoechste mit dem Zustand aus a) durch – schon bei i = 0. Überlege dann: Was bedeutet der Rückgabewert 0 bei einem leeren Gewächshaus?Hinweis zu Aufgabe d)
Erwartungshorizont
Erwartungshorizont zu Aufgabe a)
Rückgabewerte: Platz 0 true; Platz 2 Basilikum true; Platz 2 Paprika false (belegt); Platz 5 Gurke true; Platz 6 Minze false (existiert nicht, Plätze 0 bis 5); Platz 3 t true (leer). Danach leert entfernen(0) Platz 0.
| Index | 0 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|---|
beete | null | null | Basilikum | t (Tomate) | null | Gurke |
- art = "Tomate"
- feuchte = 35
- hoehe = 80
- art = "Basilikum"
- feuchte = 55
- hoehe = 20
- art = "Gurke"
- feuchte = 25
- hoehe = 120
Die Namen b und u sind frei gewählt, da diese Objekte keine eigene Variable haben. Paprika und Minze wurden zwar erzeugt, aber nirgends gespeichert; sie sind nicht mehr erreichbar. Die Tomate stand zwischenzeitlich in Platz 0 und Platz 3 (dasselbe Objekt); nach entfernen(0) bleibt nur der Verweis in Platz 3.
Erwartungshorizont zu Aufgabe b)
public Pflanze trockenste() {
Pflanze min = null;
for (int i = 0; i < beete.length; i++) {
if (beete[i] != null) {
if (min == null || beete[i].getFeuchte() < min.getFeuchte()) {
min = beete[i];
}
}
}
return min;
}
public int bewaessern(int grenze, int menge) {
int anzahl = 0;
for (int i = 0; i < beete.length; i++) {
if (beete[i] != null && beete[i].getFeuchte() < grenze) {
beete[i].giessen(menge);
anzahl++;
}
}
return anzahl;
}
Im Zustand aus a) liefert trockenste() die Gurke (25 %). g.bewaessern(40, 20) liefert 2: Tomate 35 → 55, Gurke 25 → 45, Basilikum (55) bleibt unverändert.
Erwartungshorizont zu Aufgabe c)
Leere Beete: Es fehlt die null-Prüfung. Im Zustand aus a) ist schon beete[0] gleich null; beete[0].getHoehe() löst eine NullPointerException aus. Die Methode funktioniert nur, wenn alle Beete belegt sind.
Leeres Gewächshaus: Selbst mit null-Prüfung würde 0 geliefert. Das ist nicht von „Beet 0 enthält die höchste Pflanze“ zu unterscheiden. Ein ungültiger Index wie −1 macht den Fall erkennbar.
Gleich hohe Pflanzen: Wegen > wird die erste der gleich hohen Pflanzen gefunden; das ist eine zulässige Festlegung. Der Startwert max = 0 ist unkritisch, da Höhen positiv sind, beruht aber auf dieser Annahme.
public int hoechste() {
int platz = -1;
for (int i = 0; i < beete.length; i++) {
if (beete[i] != null) {
if (platz == -1 || beete[i].getHoehe() > beete[platz].getHoehe()) {
platz = i;
}
}
}
return platz;
}
Im Zustand aus a) liefert die verbesserte Fassung 5 (Gurke, 120 cm).
Erwartungshorizont zu Aufgabe d)
Gemeinsamkeiten: Beide nutzen eine Reihung fester Länge; die Pflanzen-Objekte werden einzeln erzeugt, gespeichert werden Referenzen.
Unterschiede: Mit Lücken entspricht der Index dem realen Beet; ein Sensor an Beet 3 findet seine Pflanze direkt über beete[3]. Entfernen ist einfach (Platz auf null setzen). Dafür muss jeder Durchlauf alle Plätze prüfen und bei jedem Zugriff null abfangen. Lückenlos mit anzahl durchläuft man nur die Plätze 0 bis anzahl - 1 und braucht keine null-Prüfung; beim Entfernen müssen jedoch nachfolgende Einträge verschoben (oder der letzte Eintrag in die Lücke gesetzt) werden, und der Index sagt nichts mehr über das Beet aus – die Beetnummer müsste als zusätzliches Attribut in Pflanze gespeichert und gesucht werden.
Entscheidung: Für das Gewächshaus ist die Variante mit Lücken geeigneter, weil die Beete räumlich fest sind und die Sensoren beetweise arbeiten; die zusätzliche null-Prüfung ist ein geringer Preis. Die lückenlose Variante passt eher zu Sammlungen ohne feste Plätze, z. B. einer Liste von Anmeldungen.
