Teil 4 und 5 selbst lösen, erst dann die Lösung aufklappen
Alle Ausgaben in den Übungen wurden mit Java getestet.
Teil 1 – Objektorientierung
1.1 Klassen und Objekte
Klasse = selbst definierter Datentyp = Bauplan für Objekte
Objekt = Exemplar / Instanz einer Klasse
Eine Klasse beschreibt:
Attribute (was das Objekt hat) → Variablen / Felder / Instanzvariablen → Zustand
Operationen (was das Objekt kann) → Methoden → Verhalten
Merksatz: „Ich bin, ich habe, ich kann …”
Klassen können wie eingebaute Datentypen verwendet werden (ähnlich wie Arrays oder Strukturen/struct in C)
Klassen fassen mehrere Elemente zu einem neuen Element unter einem gemeinsamen Namen zusammen
Begriffe: Attribute + Operationen heißen zusammen Eigenschaften eines Objekts; oft werden aber nur die Attribute als Eigenschaften bezeichnet
public class Car { private String name; private int numberOfWheels;}Car a, b; // a und b sind vom Typ Car, zunächst nulla = new Car(); // Objekt erzeugen, Konstruktor wird aufgerufenb = new Car(); // gleicher Bauplan, aber andere Identität
new → die Speicherverwaltung sucht freien Speicher und gibt eine Referenz auf das neue Objekt zurück
Die Klammern bei new Car() sind der Konstruktoraufruf
1.2 Datenkapselung (Information Hiding)
Attribute sollen von außen verborgen bleiben → private
Methoden bleiben von außen zugänglich → public
Zugriff auf Attribute nur über Getter/Setter
1.3 Zugriffsattribute (Sichtbarkeit)
Zugriffsstufe
Klasse
Paket
Unterklasse
Überall
public
✅
✅
✅
✅
protected
✅
✅
✅
❌
default (kein Modifier, package-private)
✅
✅
❌
❌
private
✅
❌
❌
❌
Reihenfolge von offen nach geschlossen: public → protected → default → private
1.4 Referenzvariablen, Zuweisung, Vergleich
Car a = new Car(); → a ist eine Referenzvariable
Zugriff: referenz.attribut bzw. referenz.methode()
Referenzvariablen gleichen Typs kann man einander zuweisen → beide zeigen auf dasselbe Objekt
Jeder Referenzvariable darf null zugewiesen werden
== und != vergleichen die Referenzen (Adressen), nicht die Inhalte!
Der Typ der Variable muss mit dem Typ des erzeugten Objekts kompatibel sein
Direkter Zugriff auf private Attribute von außen sollte vermieden werden (innerhalb der Klasse aber möglich). Besser über public Methoden zugreifen.
1.5 Speicherverwaltung
Stack
Heap
lokale Variablen
mit new erzeugte Objekte
Methodenaufrufe mit Parametern
Speicher für alle Attribute + Verwaltungsinfos
Garbage Collector (GC): automatische Speicherbereinigung. Er räumt nicht mehr referenzierte Objekte auf und gibt den Speicher frei.
Heapgröße seit Java 5: ¼ des Hauptspeichers (max. 1 GiB)
Verschiedene JVMs haben verschiedene GC-Algorithmen
1.6 Methoden
Vier Fälle (wie in C):
ohne Parameter, ohne Rückgabe → void a()
mit Parameter, ohne Rückgabe → void a(int x)
ohne Parameter, mit Rückgabe → int a()
mit Parameter, mit Rückgabe → int a(int x)
Methoden stehen immer in Klassen
Statische Methoden (static) gehören zur Klasse und werden ohne Objekt aufgerufen
In Java gibt es nur Call by Value
Bei Objekten wird der Wert der Referenz kopiert. Die Methode kann also das Objekt verändern (p.x = 99), aber die Referenz-Variable des Aufrufers nicht umbiegen (p = new ... wirkt nur lokal).
1.7 Die this-Referenz
Jedes Objekt hat eine this-Referenz, einen Zeiger auf sich selbst
In jeder (nicht-statischen) Methode automatisch definiert
Unterscheidet Objektvariable von gleichnamiger lokaler Variable / Parameter
class Car { String name; // Objektvariable void printName(String name) { // Parameter System.out.println(name); // Parameter System.out.println(this.name); // Objektvariable }}
Vorteile: Kontrolle der Werte (z.B. kein negatives Alter), Hilfe bei der Fehlersuche, Information Hiding
1.9 Konstruktoren
Spezielle Methode, die bei newautomatisch aufgerufen wird → Attribute initialisieren
Gleicher Name wie die Klasse, kein Rückgabetyp (auch nicht void!), kann Parameter haben
Eine Klasse kann mehrere Konstruktoren haben (Überladen); der passende wird ausgewählt
Parameter am besten final, damit nicht versehentlich color = color; statt this.color = color; passiert
final-Parametern kann man nichts zuweisen, Änderungen am Objekt sind aber erlaubt
Default-Konstruktor
Schreibt man keinen Konstruktor, erzeugt Java automatisch einen leeren Default-Konstruktor.
Schreibt man mindestens einen Konstruktor, gibt es keinen Default-Konstruktor mehr. Dann muss man public Car() {} selbst schreiben.
Konstruktorverkettung mit this(...) (muss die erste Anweisung sein):
public Car(final int numberOfWheels, final String name) { this.numberOfWheels = numberOfWheels; this.name = name;}public Car(final String name) { this(4, name); // ruft den anderen Konstruktor auf}
Kopierkonstruktor (statt a = b, das nur die Referenz kopiert):
public Car(final Car c) { this.name = c.name; this.numberOfWheels = c.numberOfWheels;}Car car4 = new Car("Fiat", 4);Car car5 = new Car(car4); // neues Objekt, gleiche Werte
Flache Kopie: enthält das Objekt selbst Objekte oder Arrays, werden nur deren Referenzen kopiert. Änderungen wirken sich dann auf das Original aus.
Tiefe Kopie: echte Kopie inklusive aller Werte
1.10 Statische Komponenten (static)
Mit static: gehört zum Klassenobjekt, existiert einmal pro Klasse und wird von allen Objekten geteilt
Hintergrund: Auch die Klasse ist ein Objekt (Klassenobjekt = Schablone, die das Aussehen der Klasse festlegt). Klassenobjekt und Objekte können Attribute und Methoden haben.
Ohne static: gehört zum einzelnen Objekt, jedes Objekt hat eine eigene Kopie
class BankAccount { private String name; private double amount; private static int bankAccountCounter = 0; // gemeinsamer Zähler public BankAccount(final String name, final double amount) { this.name = (name != null) ? name : ""; this.amount = (amount > 0.0) ? amount : 0.0; bankAccountCounter++; } public static int getCounter() { return bankAccountCounter; }}
Objektbezogen vs. Statisch (Folie 29):
Objektbezogen
Statisch
Deklaration
ohnestatic
mitstatic
existieren
in jedem Objekt
nur einmal pro Klasse
Felder werden angelegt
wenn das Objekt erzeugt wird
wenn die Klasse geladen wird
Felder werden freigegeben
vom Garbage Collector, wenn keine Referenz mehr auf das Objekt existiert
wenn die Klasse entladen wird (am Ende des Programms)
Konstruktor wird aufgerufen
wenn das Objekt erzeugt wird
wenn die Klasse geladen wird (statischer Initialisierer)
Felder ansprechen
obj.field, this.field
Class.field
Methoden aufrufen
obj.m();, this.m();
Class.m();
Zugriffsregeln:
Objektmethoden und Konstruktoren → dürfen auf Objekt- und Klassenfelder/-methoden zugreifen
Klassenmethoden (static) → dürfen nur auf Klassenfelder/-methoden zugreifen. Es gibt kein this!
Aufruf: Klassenname.feld / Klassenname.methode(); innerhalb der Klasse geht es auch ohne Klassenname
main ist eine statische Methode
Statischer Initialisierer: kein Name, keine Parameter, nur einer pro Klasse. Läuft beim Laden der Klasse:
static { bankAccountCounter = 0;}
1.11 Strings
- String-Variablen enthalten **Referenzen** auf String-Objekte
Operator + und += zum Verketten
Strings sind unveränderlich (immutable): Jede „Änderung” erzeugt ein neues Objekt
Konstruktoren:
String s1 = "Hallo";String s2 = new String(); // ""String s3 = new String(s1); // "Hallo" (neues Objekt!)char[] charArr = {'S','W','E','2'};String s4 = new String(charArr); // "SWE2"String s5 = new String(charArr, 1, 2); // "WE" (ab Index 1, 2 Zeichen)
Wert = Differenz der ersten unterschiedlichen Zeichen (Unicode). Ist ein String Anfang des anderen, ist der Wert die Längendifferenz.
Hilfreiche Methoden (Indizes beginnen bei 0!):
String s1 = "Das ist ein spezieller Test";// 0123456789...s1.length() // 27s1.charAt(0) // Ds1.indexOf('i') // 4 erstes 'i's1.lastIndexOf('i') // 16 letztes 'i's1.indexOf('i', 5) // 9 erstes 'i' ab Index 5s1.lastIndexOf('i', 10)// 9 letztes 'i' bis Index 10 (rückwärts suchen)s1.indexOf("ei") // 8s1.substring(8) // "ein spezieller Test" ab Index 8 bis Endes1.substring(4, 15) // "ist ein spe" Index 4 bis 14 (Ende exklusiv!)
substring(von, bis)
bis ist exklusiv: substring(4, 15) liefert die Zeichen 4 bis 14, also 15 - 4 = 11 Zeichen. indexOf liefert -1, wenn nichts gefunden wird.
1.12 StringBuilder
Verhält sich wie ein String, ist aber veränderbar
Gut zum Aufbauen von Zeichenketten, weil nicht bei jeder Verkettung ein neues Objekt entsteht
Am Ende mit toString() in einen String umwandeln
Methoden geben den StringBuilder zurück, deshalb kann man sie verketten
StringBuilder sb = new StringBuilder("Test");sb.append(" SWE2"); // "Test SWE2"sb.insert(4, " und"); // "Test und SWE2"sb.delete(4, 8); // "Test SWE2" (löscht Index 4–7)sb.replace(4, 9, "string"); // "Teststring" (ersetzt Index 4–8)sb.append(" ").insert(sb.length() - 1, " SWE2").append(sb.charAt(0));System.out.println(sb.toString() + "est");// Ausgabe: Teststring SWE2 Test
Erklärung letzte Zeile
"Teststring" → append(" ") → "Teststring " → insert(10, " SWE2") (vor das Leerzeichen) → "Teststring SWE2 " → append('T') → "Teststring SWE2 T" → + "est" → Teststring SWE2 Test
(Auf der Folie ist die Ausgabe auf zwei Zeilen umgebrochen; tatsächlich steht alles in einer Zeile.)
Teil 2 – Pakete und Vererbung
2.1 Pakete
Java hat eine riesige Standardbibliothek (Java-API)
enthält tausende Typen; API = Schnittstelle der Bibliothek zum Programmierer
Nur von Klassen erben, nicht von primitiven Datentypen
Ohne extends erbt jede Klasse automatisch von java.lang.Object → class Car ≡ class Car extends Object
Deshalb hat jede Klasse z.B. toString()
Keine Mehrfachvererbung in Java (anders als in C++ oder Python)
Grund u.a. das Diamantproblem: O hat x; K1 und K2 erben von O; U erbt von K1 und K2 → Woher kommt x? Hat K1 oder K2 x verändert?
Bei gleichnamigen Methoden in 2 Oberklassen muss man in C++ die Oberklasse mit :: angeben
2.4 Konstruktoren und Vererbung
Konstruktoren werden nicht vererbt (gehören zum statischen Teil der Klasse)
in Python dagegen schon
Mit dem Konstruktor der Oberklasse kann man kein Objekt der Unterklasse erzeugen
Die Unterklasse sammelt alle sichtbaren Eigenschaften (Attribute + Methoden) der Oberklasse
Die Eigenschaften der Oberklasse müssen ggf. in deren Konstruktor initialisiert werden. Deshalb wird er immer mit aufgerufen.
Jede Unterklasse braucht eigene Konstruktoren
Java ruft in jedem Konstruktor automatisch zuerst super() auf, den Standardkonstruktor der Oberklasse
// Das schreibst du: // Das macht die Laufzeitumgebung daraus:class Car { } class Car {class Cabriolet extends Car { } Car() { super(); } // ruft Object() } class Cabriolet extends Car { Cabriolet() { super(); } // ruft Car() }
super(...):
Muss die erste Anweisung im Konstruktor sein
Kann mit Argumenten aufgerufen werden, wenn die Oberklasse keinen Standardkonstruktor hat
class Car { public String name; Car(String name) { this.name = name; }}class Cabriolet extends Car { } // ❌ COMPILERFEHLER: Car() existiert nicht!class Cabriolet extends Car { Cabriolet() { super("Volvo"); } // ✅}
super vs. this:
super()undthis() müssen beide die erste Anweisung sein → nicht gemeinsam möglich
Lösung: super(...) bleibt erste Anweisung, der restliche Code kommt in eine private Methode (z.B. initialize()) oder wird über Setter erledigt
super.super.methode() ist nicht möglich. Eine Klasse kennt nur ihre direkte Oberklasse.
Sollte überschrieben werden: Klassenname + Zustand (Attributwerte)
@Override davor schreiben (Annotation; der Compiler prüft, ob wirklich überschrieben wird)
public class Testarossa extends Ferrari { public int hubraum = 2000; @Override public String toString() { return getClass().getSimpleName() + " [name=" + name + ", hubraum=" + hubraum + "]"; // Alternative mit format: // return String.format("%s[name=%s, hubraum=%d]", getClass().getSimpleName(), name, hubraum); // Oberklassen-Version erweitern: // return super.toString() + "[name=" + name + ", hubraum=" + hubraum + "]"; }}// Ausgabe: Testarossa [name=Ferrari, hubraum=2000]// mit super.toString(): skriptum.Testarossa@4fca772d[name=Ferrari, hubraum=2000]
System.out.println(obj) ruft automatisch obj.toString() auf
2.7 Typen in Hierarchien (Upcast / Downcast)
Hierarchie aus den Folien:
Object
│
Ferrari (# String name) ← protected
/ \
California Testarossa (- int hubraum)
Implizite Typumwandlung (Upcast), geht automatisch:
Ferrari testarossaIsFerrari = new Testarossa(); // Unterklasse → Oberklasse ✅Object testarossaIsObject = new Testarossa(); // ✅
Referenztyp vs. Objekttyp
Referenztyp (Compilertyp) = Typ der Variable → bestimmt, was man aufrufen darf
Objekttyp (JVM-/Laufzeittyp) = Typ von new ... → bestimmt, welche überschriebene Methode ausgeführt wird
Ferrari f = new Testarossa();System.out.println(f.name); // ✅ name ist in FerrariSystem.out.println(f.hubraum); // ❌ Compilerfehler: hubraum cannot be resolved // (Compiler sieht nur Ferrari!)Testarossa t = f; // ❌ Type mismatch: cannot convert from Ferrari to TestarossaTestarossa t = (Testarossa) f; // ✅ expliziter Cast (Downcast)System.out.println(t.hubraum); // ✅
Fehler beim Cast: ClassCastException (zur Laufzeit!)
Ferrari californiaIsFerrari = new California();Testarossa meinFerrari = (Testarossa) californiaIsFerrari;// kompiliert ✅, aber zur Laufzeit: ClassCastException// (California ist kein Testarossa)
2.8 Liskovsches Substitutionsprinzip
Benannt nach Barbara Liskov
Überall, wo ein Objekt der Oberklasse erwartet wird, darf auch ein Objekt einer Unterklasse verwendet werden
public static void showNameAndHubraum(Ferrari ferrari) { System.out.println(ferrari.name);}showNameAndHubraum(testarossaIsFerrari); // ✅showNameAndHubraum(californiaIsFerrari); // ✅// println(Object) nimmt deshalb jedes beliebige Objekt an
2.9 instanceof
Prüft zur Laufzeit, ob eine Referenz ≠ null ist und einen bestimmten Typ hat
Die Typen müssen in einer Hierarchie stehen, sonst Compilerfehler
"Hallo" instanceof StringBuilder // ❌ Compilerfehler (String/StringBuilder nicht verwandt)Object meinFerrari = new Testarossa();meinFerrari instanceof Testarossa // truemeinFerrari instanceof Ferrari // truemeinFerrari instanceof Object // truemeinFerrari instanceof California // falsemeinFerrari instanceof String // falsenull instanceof Object // false
Typisch: erst prüfen, dann casten:
if (obj instanceof Testarossa) { Testarossa t = (Testarossa) obj;}
2.10 final bei Klassen und Methoden
Wirkung
final class
Es können keine Unterklassen gebildet werden (z.B. String, StringBuilder, Integer, Double, Math, System)
final Methode
kann in Unterklassen nicht überschrieben werden
final Variable/Parameter
kann nach der Zuweisung nicht mehr geändert werden
private Methoden können nicht überschrieben werden, sie werden verdeckt (wie Attribute)
2.11 Polymorphie und dynamisches Binden
Testarossa a = new Testarossa();Ferrari b = new Testarossa();Object c = new Testarossa();System.out.println(a.toString()); // Testarossa [name=Ferrari, hubraum=2000]System.out.println(b.toString()); // Testarossa [name=Ferrari, hubraum=2000]System.out.println(c.toString()); // Testarossa [name=Ferrari, hubraum=2000]
Der Compiler würde bei b und c toString() aus Object erwarten. Die Laufzeitumgebung schaut aber auf den echten Objekttyp und nimmt die überschriebene Methode → spätes / dynamisches Binden = Polymorphie
Ausnahmen: NICHT dynamisch gebunden werden
private Methoden
static Methoden
final Methoden
Attribute (Felder) werden nie dynamisch gebunden. Es zählt der Referenztyp!
int a = 1; // in Oberklasseint a = 2; // in Unterklasse (verdeckt das Attribut)// in der Unterklasse:System.out.println(super.a); // 1System.out.println(a); // 2
Übungen aus den Folien
Übung Auto (Folie 17)
Klasse Car mit Attributen Name, Zulassungsjahr, Höchstgeschwindigkeit, Farbe (Datentyp selbst wählen)
main-Methode: drei Exemplare erzeugen und sinnvolle Werte zuweisen
Methoden ohne Rückgabewert:
fahre(speed) → Ausgabe z.B. „Fiat fährt 100 Km/h.”
gibFarbeAus() → gibt die Farbe aus
gibAlterAus() → berechnet das Alter des Autos
Übung Rechteck (Folie 22)
Eigenschaften: Länge, Breite, Fläche, Umfang, Länge der Diagonalen
Klasse Rectangle mit den Konstruktoren:
Rectangle() → Länge 1, Breite 1
Rectangle(float l, float b) → Länge l, Breite b
a) nur mit Konstruktoren arbeiten und alle Werte dort ausgeben
b) Getter für alle Attribute schreiben und die Werte in main ausgeben
Formeln: Fläche l * b, Umfang 2 * (l + b), Diagonale Math.sqrt(l*l + b*b)
Deine Lösungen liegen in Informatik/Skripte/01_Uebung und 02_Uebung.
Teil 3 – Typische Fallen (Kurzüberblick)
Situation
Ergebnis
a == b bei Objekten
vergleicht Referenzen, nicht Inhalte
"abc" == "abc"
true (String-Pool)
new String("abc") == "abc"
false
s.toUpperCase(); ohne Zuweisung
s bleibt unverändert (immutable)
eigener Konstruktor mit Parametern, dann new X()
Compilerfehler, kein Default-Konstruktor mehr
Oberklasse hat nur X(String), Unterklasse ohne super("...")
Compilerfehler
super() / this() nicht als erste Zeile
Compilerfehler
super() und this() im selben Konstruktor
Compilerfehler
Ober o = new Unter(); o.methodeNurInUnter();
Compilerfehler
Unter u = (Unter) new Ober();
kompiliert, ClassCastException zur Laufzeit
Ober o = new Unter(); o.ueberschriebeneMethode()
Methode der Unterklasse (dynamisches Binden)
Ober o = new Unter(); o.attribut
Attribut der Oberklasse (Referenztyp zählt)
Ober o = new Unter(); o.staticMethode()
Methode der Oberklasse (static wird nicht dynamisch gebunden)
this in static Methode
Compilerfehler
Objektvariable in static Methode verwenden
Compilerfehler
class B extends A, C
Compilerfehler, keine Mehrfachvererbung
class X extends String
Compilerfehler, String ist final
1 + 2 + "3" + 4 + 5
"3345" (links nach rechts: erst 3, dann String)
Teil 4 – Übungen: Was ist die Ausgabe?
Aufgabe 1 – Vererbung, Konstruktoren, Polymorphie
class Tier { protected String name = "Tier"; int a = 1; static int zaehler = 0; Tier() { System.out.println("Konstruktor Tier"); zaehler++; } Tier(String n) { this(); name = n; System.out.println("Tier(" + n + ")"); } public String laut() { return "..."; } public static String info() { return "static Tier"; } @Override public String toString() { return "Tier[" + name + "]"; }}class Hund extends Tier { int a = 2; Hund() { super("Hund"); System.out.println("Konstruktor Hund"); } @Override public String laut() { return "Wuff"; } public static String info() { return "static Hund"; } void zeige() { System.out.println(a + " " + super.a + " " + this.a); }}// in main:Tier t = new Hund();System.out.println(t.laut());System.out.println(t);System.out.println(t.a);System.out.println(((Hund) t).a);System.out.println(t.info());((Hund) t).zeige();
class Katze extends Tier { @Override public String laut() { return "Miau"; }}// in main, direkt nach Aufgabe 1:Tier k = new Katze();System.out.println(k.laut() + " " + k.name);System.out.println(Tier.zaehler);System.out.println(k instanceof Tier);System.out.println(k instanceof Hund);System.out.println(t instanceof Hund);Hund h = (Hund) k;
Katze hat keinen eigenen Konstruktor → Default-Konstruktor ruft super() → Konstruktor Tier
name wurde nie geändert → "Tier"
zaehler ist static, also für alle gemeinsam: Hund + Katze → 2
(Hund) k kompiliert (Tier → Hund ist ein möglicher Downcast), aber k ist eine Katze → ClassCastException zur Laufzeit
Aufgabe 3 – Call by Value und Referenzen
class Punkt { int x; Punkt(int x) { this.x = x; } }static void aendere(int z, Punkt p) { z = 99; p.x = 99; p = new Punkt(5); p.x = 7;}// in main:int z = 1;Punkt p = new Punkt(1);aendere(z, p);System.out.println(z + " " + p.x);Punkt q = p;q.x = 3;System.out.println(p.x + " " + (p == q));Punkt r = new Punkt(3);System.out.println(p == r);
Lösung
1 99
3 true
false
z ist primitiv → Kopie → bleibt 1
p.x = 99 ändert das echte Objekt; p = new Punkt(5) ändert nur die lokale Kopie der Referenz → p.x ist 99
q = p → beide zeigen auf dasselbe Objekt → p.x ist 3, p == q ist true
r ist ein anderes Objekt (gleicher Inhalt) → == ist false
class A { A(int x) { } }class B extends A { } // (a)class C { C(String s) { } }// in main: C c = new C(); // (b)class D { int wert; static void m() { System.out.println(this.wert); } // (c)}class E extends D { E() { this(5); super(); } // (d) E(int x) { }}final class F { }class G extends F { } // (e)Object o = new String("x");System.out.println(o.length()); // (f)import java.*; // (g)import java.util.Da*; // (h)
Lösung
(a) ❌ B hat einen Default-Konstruktor mit super(), aber A() existiert nicht
(b) ❌ Es gibt einen eigenen Konstruktor → kein Default-Konstruktor mehr
(c) ❌ In einer static Methode gibt es kein this
(d) ❌ this() und super() gemeinsam geht nicht, beide müssten die erste Anweisung sein
(e) ❌ von einer final Klasse kann man nicht erben
(f) ❌ Referenztyp ist Object, das hat kein length() → Cast nötig: ((String) o).length()
(g) ✅ syntaktisch korrekt, aber sinnlos
(h) ❌ Stern nur als ganze letzte Ebene erlaubt
Teil 5 – Übungen: Code vervollständigen
Aufgabe 7 – Klasse Person
Vervollständige die Klasse:
private Attribute name (String) und alter (int)
statischer Zähler anzahl, der jedes erzeugte Objekt mitzählt
Konstruktor Person(String name, int alter)
Konstruktor Person(String name) → Alter 0, Konstruktorverkettung verwenden
Kopierkonstruktor
Getter für beide Attribute, Setter für alter (negative Werte → 0)
statischer Getter für anzahl
toString() überschreiben → Person [name=Anna, alter=17]
package it.fallmerayer;class Person { _______ String name; _______ int alter; _______ _______ int anzahl = 0; public Person(final String name, final int alter) { ____________________ ____________________ ____________________ } public Person(final String name) { ____________________ } public Person(final Person p) { ____________________ } // Getter, Setter, getAnzahl, toString ...}
Lösung
package it.fallmerayer;class Person { private String name; private int alter; private static int anzahl = 0; public Person(final String name, final int alter) { this.name = name; setAlter(alter); anzahl++; } public Person(final String name) { this(name, 0); } public Person(final Person p) { this(p.name, p.alter); } public String getName() { return name; } public int getAlter() { return alter; } public void setAlter(final int alter) { this.alter = (alter >= 0) ? alter : 0; } public static int getAnzahl() { return anzahl; } @Override public String toString() { return getClass().getSimpleName() + " [name=" + name + ", alter=" + alter + "]"; }}
Aufgabe 8 – Unterklasse Schueler
Erstelle Schueler als Unterklasse von Person mit dem zusätzlichen Attribut klasse (String). Der Konstruktor soll den Konstruktor der Oberklasse verwenden. toString() soll die Version der Oberklasse erweitern.
class Schueler ________ Person { private String klasse; public Schueler(final String name, final int alter, final String klasse) { ____________________ ____________________ } ____________ public String toString() { return ____________________ + "[klasse=" + klasse + "]"; }}
Lösung
class Schueler extends Person { private String klasse; public Schueler(final String name, final int alter, final String klasse) { super(name, alter); // MUSS erste Zeile sein this.klasse = klasse; } @Override public String toString() { return super.toString() + "[klasse=" + klasse + "]"; }}
Aufgabe 9 – Was gibt main aus? (mit Aufgabe 7 + 8)
public class Main { public static void main(String[] args) { Person a = new Person("Anna", 17); Person b = new Person("Ben"); Person c = new Person(a); Person s = new Schueler("Leon", 17, "4BT"); b.setAlter(-5); System.out.println(a); System.out.println(b); System.out.println(a == c); System.out.println(s); System.out.println(Person.getAnzahl()); if (s instanceof Schueler) { Schueler sch = (Schueler) s; System.out.println(sch.getName()); } }}
Lösung
Person [name=Anna, alter=17]
Person [name=Ben, alter=0]
false
Schueler [name=Leon, alter=17][klasse=4BT]
4
Leon
a == c → Kopierkonstruktor erzeugt ein neues Objekt → false
s → getClass().getSimpleName() liefert den echten Typ Schueler, toString() von Schueler (dynamisches Binden)
Zähler: Anna, Ben, Kopie, Leon → 4 (auch super(...) im Schueler zählt mit)
Aufgabe 10 – Ergänze die Lücken (Theorie)
Eine Klasse ist ein ____ für Objekte.
Attribute sollten ____ sein, Methoden meist ____.
Der Konstruktor hat den gleichen Namen wie die ____ und keinen ____.
== vergleicht bei Objekten die ____, equals() den ____.
Objekte liegen im ____, lokale Variablen im ____.
Jede Klasse erbt direkt oder indirekt von ____.
Mit dem Schlüsselwort ____ erbt eine Klasse von einer anderen.
super() muss die ____ Anweisung im Konstruktor sein.