Aufgabenblock — AFB I
Zehn Standardaufgaben quer durch das ganze Kapitel — bunt gemischt statt nach Unterkapiteln sortiert: Klassenkarten und Objektkarten lesen, Zustände nach Methodenaufrufen angeben, einfache Klassen notieren, Referenzen, Reihungen und Zeichenketten-Methoden. Das sind die sicheren Punkte in jeder Klausur zur Objektorientierung.
Eine Playlist-App verwendet die folgende Klasse. Entnehmen Sie der Klassenkarte, wie viele Parameter der Konstruktor hat und wie viele der Methoden Anfragen bzw. Aufträge sind.
- - titel: Zeichenkette
- - interpret: Zeichenkette
- - dauerSek: Ganzzahl
- - favorit: Wahrheitswert
- c Song(titel: Zeichenkette, interpret: Zeichenkette, dauerSek: Ganzzahl)
- + getTitel(): Zeichenkette
- + getDauerSek(): Ganzzahl
- + istFavorit(): Wahrheitswert
- + markieren()
- + setDauerSek(dauerSek: Ganzzahl)
+.Vollständige Lösung
Der Konstruktor c Song(titel, interpret, dauerSek) hat 3 Parameter. favorit wird nicht übergeben, sondern im Konstruktor auf false gesetzt.
Anfragen (3): getTitel(): Zeichenkette, getDauerSek(): Ganzzahl, istFavorit(): Wahrheitswert — sie haben einen Rückgabetyp.
Aufträge (2): markieren() und setDauerSek(dauerSek: Ganzzahl) — kein Rückgabetyp, sie ändern den Zustand.
Beachte: Für interpret gibt es keinen Getter. Das Attribut ist privat und damit von außen weder lesbar noch änderbar — ob das so gewollt ist, müsste man im Entwurf klären.
Die Methode kaffeeZubereiten() verbraucht 14 g Bohnen und erhöht becher um 1 — aber nur, wenn noch mindestens 14 g vorhanden sind. auffuellen(gramm) erhöht den Bohnenvorrat.
Kaffeeautomat k = new Kaffeeautomat(40); k.kaffeeZubereiten(); k.kaffeeZubereiten(); k.kaffeeZubereiten(); k.auffuellen(30); k.kaffeeZubereiten();
Geben Sie die Attributwerte des Objekts k nach allen Aufrufen an.
bohnenGramm und becher fortschreiben.bohnenGramm >= 14 nicht erfüllt ist?Vollständige Lösung
Die Methode im Quelltext:
public class Kaffeeautomat {
private int bohnenGramm;
private int becher;
public Kaffeeautomat(int bohnenGramm) {
this.bohnenGramm = bohnenGramm;
becher = 0;
}
public void kaffeeZubereiten() {
if (bohnenGramm >= 14) {
bohnenGramm = bohnenGramm - 14;
becher = becher + 1;
}
}
public void auffuellen(int gramm) {
bohnenGramm = bohnenGramm + gramm;
}
public int getBohnenGramm() {
return bohnenGramm;
}
public int getBecher() {
return becher;
}
}
Ablauf: 40 g / 0 → 26 g / 1 → 12 g / 2 → dritter Aufruf: 12 < 14, nichts passiert → auffüllen: 42 g / 2 → 28 g / 3.
- bohnenGramm = 28
- becher = 3
Typischer Fehler: 4 Becher und 0 g — dann wurde die Bedingung im dritten Aufruf übersehen.
- bohnenGramm = 40
- becher = 0
Die Anzeige im Schulbus speichert den Namen der nächsten Haltestelle: String h = "Am Rathausplatz";
Nennen Sie die Rückgaben von h.length() und h.indexOf("platz"). Nennen Sie außerdem die Rückgaben von h.substring(3, 10) und h.charAt(h.length() - 1).
indexOf liefert den Index des ersten Zeichens des gefundenen Teilstrings. substring(a, b) liefert die Zeichen von Index a bis ausschließlich b.length() − 1, nie length().Vollständige Lösung
Indizes: A0 m1 ␣2 R3 a4 t5 h6 a7 u8 s9 p10 l11 a12 t13 z14
h.length() → 15 (Indizes 0 bis 14).
h.indexOf("platz") → 10 („p“ steht an Index 10).
h.substring(3, 10) → "Rathaus" (Index 3 bis 9; Index 10 gehört nicht mehr dazu).
h.charAt(h.length() - 1) → das Zeichen 'z' (Index 14). h.charAt(h.length()) würde dagegen einen Laufzeitfehler auslösen.
Ein Gewächshaus-Programm verwaltet Pflanzen. Die Höhe soll nur Werte von 0 bis 500 cm annehmen; ungültige Werte werden ignoriert. Nach dem Erzeugen ist die Höhe 0.
- - art: Zeichenkette
- - hoeheCm: Ganzzahl
- c Pflanze(art: Zeichenkette)
- + getHoeheCm(): Ganzzahl
- + setHoeheCm(hoeheCm: Ganzzahl)
Stellen Sie die Klasse vollständig als Java-Quelltext dar.
private), Konstruktor (ohne Rückgabetyp, auch ohne void), dann die Methoden.this. würdest du nur den Parameter mit sich selbst überschreiben. Die Zuweisung steht in einem if mit der Bereichsprüfung.Vollständige Lösung
public class Pflanze {
private String art;
private int hoeheCm;
public Pflanze(String art) {
this.art = art;
hoeheCm = 0;
}
public int getHoeheCm() {
return hoeheCm;
}
public void setHoeheCm(int hoeheCm) {
if (hoeheCm >= 0 && hoeheCm <= 500) {
this.hoeheCm = hoeheCm;
}
}
}
Häufige Fehler: public void Pflanze(...) ist kein Konstruktor, sondern eine Methode; hoeheCm = hoeheCm; ohne this ändert das Attribut nicht; ein Getter ohne return kompiliert nicht.
Gegeben ist der Quelltext einer Klasse aus der Kundenverwaltung eines Mobilfunkanbieters.
public class Handyvertrag {
private String nummer;
private int datenvolumenMB;
private int verbrauchtMB;
private boolean gesperrt;
public Handyvertrag(String nummer, int datenvolumenMB) {
this.nummer = nummer;
this.datenvolumenMB = datenvolumenMB;
verbrauchtMB = 0;
gesperrt = false;
}
public int getRestMB() {
return datenvolumenMB - verbrauchtMB;
}
public void surfen(int mb) {
if (!gesperrt) {
verbrauchtMB = verbrauchtMB + mb;
pruefen();
}
}
public boolean istGesperrt() {
return gesperrt;
}
private void pruefen() {
if (verbrauchtMB >= datenvolumenMB) {
gesperrt = true;
}
}
}
Zeichnen Sie die zugehörige Klassenkarte in der Notation der Ergänzenden Hinweise.
private wird zu -, public zu +.int → Ganzzahl, String → Zeichenkette, boolean → Wahrheitswert. Der Konstruktor bekommt ein vorangestelltes c; void wird einfach weggelassen.getRestMB() hat kein gleichnamiges Attribut: Der Wert wird berechnet.Vollständige Lösung
- - nummer: Zeichenkette
- - datenvolumenMB: Ganzzahl
- - verbrauchtMB: Ganzzahl
- - gesperrt: Wahrheitswert
- c Handyvertrag(nummer: Zeichenkette, datenvolumenMB: Ganzzahl)
- + getRestMB(): Ganzzahl
- + surfen(mb: Ganzzahl)
- + istGesperrt(): Wahrheitswert
- - pruefen()
Nur die Attribute kommen ins mittlere Feld — lokale Variablen oder berechnete Werte wie der Rest nicht. pruefen() ist eine private Hilfsmethode und wird mit - notiert.
Die Klasse Tracker hat ein Attribut schritte (Start 0), eine Methode schritteAddieren(anzahl) und den Getter getSchritte().
Tracker a = new Tracker("Mia");
a.schritteAddieren(4200);
Tracker b = a;
b.schritteAddieren(800);
int s = a.getSchritte();
s = s + 1000;
Tracker c = new Tracker("Mia");
c.schritteAddieren(s);
Bestimmen Sie die Rückgaben von a.getSchritte() und c.getSchritte() nach dem letzten Befehl sowie die Anzahl der erzeugten Tracker-Objekte.
new. Jede Variable vom Typ Tracker ist nur ein Verweis auf ein Objekt.b = a zeigen beide Variablen auf dasselbe Objekt. s ist dagegen eine int-Variable: Sie enthält eine Kopie des Werts.Vollständige Lösung
Es gibt 2 Objekte (zweimal new). a und b verweisen auf dasselbe Objekt: 4200 + 800 = 5000. s erhält eine Kopie dieses Werts; s = s + 1000; ändert nur s (6000), nicht das Objekt. Das zweite Objekt c hat trotz gleichem Namen „Mia“ eine eigene Identität und bekommt 6000 Schritte.
- name = "Mia"
- schritte = 5000
- name = "Mia"
- schritte = 6000
Die linke Karte ist das Objekt, auf das a und b verweisen.
Ein Kurs entwickelt im Team eine App, mit der sich Teilnehmende einer Klassenfahrt in Zimmer eintragen. Ordnen Sie jede Tätigkeit einer Projektphase (Analyse, Entwurf, Implementierung, Test) zu.
- Mit der Lehrkraft wird geklärt, dass ein Zimmer höchstens vier Betten hat und Jungen und Mädchen getrennt wohnen.
- Das Team legt fest: Die Klasse
Zimmerbekommt die Methode+ belegen(t: Teilnehmer): Wahrheitswert. - Es wird notiert: „Ein fünfter Teilnehmer in einem vollen Viererzimmer →
belegenliefertfalse.“ - Jonas schreibt die Methode
belegenin Java. - Die Anforderungen werden in einem Pflichtenheft zusammengefasst.
- Das Klassendiagramm wird im Team abgestimmt, bevor jemand programmiert.
Vollständige Lösung
a) Analyse — fachliche Anforderung klären. b) Entwurf — Methodensignatur festlegen. c) Test — Testfall mit erwartetem Ergebnis. d) Implementierung. e) Analyse — das Pflichtenheft ist ihr Ergebnis. f) Entwurf — das abgestimmte Klassendiagramm ist die Schnittstelle, an die sich alle beim Programmieren halten.
Ein Aquariumprogramm speichert die Fische eines Beckens in einer Reihung.
Fisch[] becken = new Fisch[6];
becken[0] = new Fisch("Guppy", 4);
becken[2] = new Fisch("Neon", 3);
becken[5] = becken[0];
Fisch f = new Fisch("Wels", 12);
Geben Sie an, wie viele Fisch-Objekte nach diesen Anweisungen existieren und wie viele Plätze der Reihung becken den Wert null haben.
new Fisch[6] erzeugt nur sechs leere Plätze, noch keinen einzigen Fisch.new. Es wird nur eine Referenz kopiert. Und f steht gar nicht in der Reihung.Vollständige Lösung
Objekte entstehen nur durch new Fisch(...): Guppy, Neon, Wels → 3 Objekte. In der Reihung sind die Plätze 0, 2 und 5 belegt (0 und 5 verweisen auf denselben Guppy), die Plätze 1, 3 und 4 sind null.
Die Reihung selbst ist zwar auch ein Objekt, aber kein Fisch-Objekt. Ein Zugriff wie becken[1].getArt() würde eine NullPointerException auslösen.
In der Steuerung eines Escape-Rooms kennt jeder Raum sein Schloss.
- - name: Zeichenkette
- - schloss: Schloss
- c Raum(name: Zeichenkette, schloss: Schloss)
- + getSchloss(): Schloss
- + betreten(): Wahrheitswert
- - code: Zeichenkette
- - offen: Wahrheitswert
- c Schloss(code: Zeichenkette)
- + oeffnen(versuch: Zeichenkette)
- + istOffen(): Wahrheitswert
Beschreiben Sie, wie die Assoziation „hat“ im Quelltext umgesetzt wird und was beim Aufruf r.getSchloss().oeffnen("4711") geschieht. Gehen Sie auch darauf ein, was passiert, wenn das Attribut schloss den Wert null hat.
Raum ein Attribut, dessen Typ eine andere Klasse ist.r.getSchloss() eine Referenz, dann wird auf diesem Objekt oeffnen aufgerufen.Vollständige Lösung
Die Assoziation wird durch das Attribut - schloss: Schloss in Raum umgesetzt: Ein Raum speichert eine Referenz auf ein Schloss-Objekt, das ihm im Konstruktor übergeben wird. Das Schloss selbst kennt den Raum nicht.
public class Raum {
private String name;
private Schloss schloss;
public Raum(String name, Schloss schloss) {
this.name = name;
this.schloss = schloss;
}
public Schloss getSchloss() {
return schloss;
}
public boolean betreten() {
return schloss.istOffen();
}
}
Bei r.getSchloss().oeffnen("4711") liefert getSchloss() die Referenz auf das Schloss des Raums r. Auf diesem Objekt wird oeffnen("4711") aufgerufen: Stimmt der Versuch mit code überein (Vergleich mit equals), wird offen auf true gesetzt. Danach liefert r.betreten() den Wert true, weil der Raum die Anfrage an sein Schloss weitergibt (Delegation).
Ist schloss gleich null, liefert getSchloss() null, und der Aufruf von oeffnen auf null führt zur NullPointerException.
Eine Quiz-App vergleicht die Eingabe mit der hinterlegten Lösung. Die Eingabe entsteht zur Laufzeit aus Teilstücken.
String loesung = "Paris";
String eingabe = "PARIS".substring(0, 1) + "aris";
int punkte = 0;
if (eingabe == loesung) {
punkte = punkte + 1;
}
if (eingabe.equals(loesung)) {
punkte = punkte + 2;
}
if (eingabe.toUpperCase().equals("PARIS")) {
punkte = punkte + 4;
}
Wenden Sie die drei Vergleiche auf die Zeichenketten an und geben Sie den Wert von punkte am Ende an.
eingabe? Setze "P" und "aris" zusammen.== vergleicht bei Objekten die Referenzen. Eine Zeichenkette, die erst zur Laufzeit zusammengesetzt wird, ist ein neues Objekt — auch wenn der Inhalt gleich ist.toUpperCase() liefert eine neue Zeichenkette in Großbuchstaben; equals vergleicht den Inhalt.Vollständige Lösung
eingabe enthält „Paris“, ist aber ein neues String-Objekt. Deshalb ist eingabe == loesung false (verschiedene Referenzen) → keine Punkte. eingabe.equals(loesung) vergleicht den Inhalt → true, +2. "PARIS".equals("PARIS") → true, +4.
punkte = 0 + 2 + 4 = 6. Wer 7 erhält, hat == fälschlich als Inhaltsvergleich gelesen — genau deshalb vergleicht man Zeichenketten immer mit equals.
