MINT lernen

Abituraufgaben: Reihungen von Objekten

Klassenfahrtkasse und Gewächshausbeete: Reihungen füllen, mit null-Prüfung durchlaufen und Summe, Minimum und Suche bilden.

Dein Fortschritt:
0 / 0 Aufgaben
1

Kasse für die Klassenfahrt nach Berlin

AFB I–II

Fü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.

Material 1: Klasse Teilnehmer und Testausschnitt
Teilnehmer
  • - 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();
    }
}
Beträge in Euro. einzahlen erhöht bezahlt um einen positiven Betrag.
Material 2: Klasse Klassenfahrt (Auszug)
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.
  1. Bestimmen Sie für Material 1 die Anzahl der erzeugten Teilnehmer-Objekte, den Wert von gruppe[1].getBezahlt() und den Wert von summe nach dem Durchlauf.
  2. Erläutern Sie, was die Anweisung new Teilnehmer[5] erzeugt und welche Folge es hätte, wenn in der Schleife aus Material 1 die Abfrage gruppe[i] != null fehlte.
  3. Erweitern Sie die Klasse Klassenfahrt um die Methode getOffen(): Ganzzahl, die den insgesamt noch fehlenden Betrag aller Angemeldeten liefert (Überzahlungen werden nicht verrechnet), und um die Methode suchen(name: Zeichenkette): Teilnehmer, die die erste Person mit diesem Namen liefert oder null, falls es keine gibt.

Hinweise

Hinweis zu Aufgabe a)
Zähle die Konstruktoraufrufe mit runden Klammern, z. B. new Teilnehmer("Mia", 180) – nicht die mit eckigen. Was steht nach gruppe[4] = gruppe[1]; in Platz 4?
Hinweis zu Aufgabe b)
Welcher Platz der Reihung wurde nie belegt? Was passiert, wenn man über diesen Platz eine Methode aufruft?
Hinweis zu Aufgabe c)
Beide Methoden durchlaufen alle Plätze und prüfen zuerst auf 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.

2

Automatische Bewässerung im Schulgewächshaus

AFB II–III

Die 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.

Material 3: Klassen und Testfolge
Gewaechshaus
  • - beete: Reihung vom Typ Pflanze
  • c Gewaechshaus(anzahl: Ganzzahl)
  • + einsetzen(platz: Ganzzahl, p: Pflanze): Wahrheitswert
  • + entfernen(platz: Ganzzahl)
  • + hoechste(): Ganzzahl
hat1n
Pflanze
  • - 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;
}
Feuchte in Prozent, Höhe in cm. Die Methode hoechste soll die Nummer des Beetes mit der höchsten Pflanze liefern.
  1. Stellen Sie die Belegung der Reihung beete nach Ausführung der Testfolge dar, geben Sie die Rückgabewerte der sechs einsetzen-Aufrufe an und stellen Sie die vorhandenen Pflanzen-Objekte als Objektkarten dar.
  2. Implementieren Sie die Methoden trockenste(): Pflanze, die die Pflanze mit der geringsten Feuchte liefert (null bei leerem Gewächshaus), und bewaessern(grenze: Ganzzahl, menge: Ganzzahl): Ganzzahl, die jede Pflanze mit einer Feuchte unter grenze mit menge gießt und die Anzahl der gegossenen Pflanzen liefert. Geben Sie das Ergebnis von g.bewaessern(40, 20) für den Zustand aus a) an.
  3. Analysieren Sie die Methode hoechste aus 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.
  4. 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 Attribut anzahl die Zahl der Pflanzen angibt, und entscheiden Sie begründet, welche Variante für das Gewächshaus geeigneter ist.

Hinweise

Hinweis zu Aufgabe a)
Die Reihung hat die Plätze 0 bis 5. Prüfe bei jedem Aufruf: Existiert der Platz? Ist er leer? Achte darauf, welche Objekte mehrfach vorkommen.
Hinweis zu Aufgabe b)
Merke dir in 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)
Spiele 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)
Kriterien: Zusammenhang zwischen Index und realem Beet, Aufwand beim Entfernen, Aufwand beim Durchlaufen, Fehleranfälligkeit.

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.

Index012345
beetenullnullBasilikumt (Tomate)nullGurke
t: Pflanze
  • art = "Tomate"
  • feuchte = 35
  • hoehe = 80
b: Pflanze
  • art = "Basilikum"
  • feuchte = 55
  • hoehe = 20
u: Pflanze
  • 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.