Zurück zur StartseiteInformatik · Q1 Leistungskurs · Fach wechseln
Kostenlos starten
Q1 Leistungskurs · Informatik
Datenbanken, Datenstrukturen und Automaten in der Qualifikationsphase · Objektorientierung, Datenstrukturen und Algorithmen

Klassen, Vererbung und UML

Eine Verkehrssimulation für Köln soll Autos, Busse und Fahrräder verwalten. Alle haben eine Position und eine Geschwindigkeit, und alle müssen sich in jedem Zeitschritt bewegen, aber jedes Fahrzeug auf seine Weise. Wie schreiben Sie den Code so, dass nichts doppelt dasteht und ein neuer Fahrzeugtyp ohne große Umbauten dazukommt? Genau dafür gibt es Klassen, Vererbung und Polymorphie.

Klasse, Objekt und UML-Klassendiagramm

Eine Klasse ist ein Bauplan. Sie legt fest, welche Daten (Attribute) und welches Verhalten (Methoden) ihre Exemplare haben. Ein Objekt ist ein konkretes Exemplar einer Klasse mit eigenen Attributwerten. Die Klasse Fahrrad gibt es einmal, Objekte davon beliebig viele.

Das UML-Klassendiagramm zeichnet eine Klasse als Rechteck mit drei Abschnitten: Klassenname, Attribute, Methoden. Attribute stehen als name: Typ, Methoden als name(parameter: Typ): Rückgabetyp. Das Zeichen vor dem Namen gibt die Sichtbarkeit an: - für private, + für public.

UML-Klassendiagramm der Klasse Fahrrad mit zwei Attributen und einer Methode, daneben ein Objekt Fahrrad - farbe: String - gaenge: int + schalte(g: int): void + getGaenge(): int Instanz meinRad: Fahrrad farbe = "rot" gaenge = 21

In Java sieht die Klasse so aus. Der Konstruktor trägt den Klassennamen, hat keinen Rückgabetyp und setzt den Anfangszustand. Mit this ist das eigene Objekt gemeint.

public class Fahrrad {

    private String farbe;

    private int gaenge;

    public Fahrrad(String farbe, int gaenge) {

        this.farbe = farbe;

        this.gaenge = gaenge;

    }

    public void schalte(int g) {

        gaenge = g;

    }

}

// Objekt erzeugen:

Fahrrad meinRad = new Fahrrad("rot", 21);
Üben★☆☆Nicht begonnen
Eine Klasse Fahrrad hat die Attribute farbe (String) und gaenge (int) sowie die Methode schalte(int g). a) Zeichnen Sie das UML-Klassendiagramm (als Text mit drei…

Eine Klasse Fahrrad hat die Attribute farbe (String) und gaenge (int) sowie die Methode schalte(int g).

  1. a) Zeichnen Sie das UML-Klassendiagramm (als Text mit drei Abschnitten).
  1. b) Erklären Sie den Unterschied zwischen Klasse und Objekt und geben Sie ein Beispielobjekt an.
Lösen

Kapselung und Sichtbarkeit

Wäre gaenge öffentlich, könnte jeder Code meinRad.gaenge = -5; schreiben. Das Objekt hätte dann einen unsinnigen Zustand. Deshalb gilt das Geheimnisprinzip (Kapselung): Attribute sind private, der Zugriff läuft über öffentliche Methoden, die Werte prüfen können.

Modifizierer Zugriff möglich von
private nur innerhalb der eigenen Klasse
protected eigene Klasse, Unterklassen und Klassen im selben Paket
public von überall

Lesender Zugriff erfolgt über einen Getter (getStand()), schreibender über einen Setter oder eine fachlich benannte Methode wie einzahlen.

Üben★☆☆Nicht begonnen
Gegeben ist die Klasse a) Erklären Sie die Bedeutung von private und public. b) Ergänzen Sie eine Methode einzahlen(double betrag), die nur positive Beträge akzeptiert.

Gegeben ist die Klasse

public class Konto {

    private double stand;

    public double getStand() { return stand; }

}
  1. a) Erklären Sie die Bedeutung von private und public.
  1. b) Ergänzen Sie eine Methode einzahlen(double betrag), die nur positive Beträge akzeptiert.
Lösen

Vererbung

Hund und Katze haben beide einen Namen und ein Alter, nur Bellen und Miauen unterscheiden sie. Was alle gemeinsam haben, steht einmal in der Oberklasse Tier. Die Unterklassen Hund und Katze erben es und ergänzen oder ändern nur das Besondere. Es gilt die ist-ein-Beziehung: Ein Hund ist ein Tier.

UML-Vererbungsdiagramm: Die Klassen Hund und Katze erben von Tier Tier # name: String + lautGeben(): String Hund + apportiere() Katze + kratze()

In UML zeigt ein Pfeil mit unausgefülltem Dreieck von der Unterklasse zur Oberklasse. Attribute, die Unterklassen direkt nutzen sollen, werden protected (UML: #). Sie stehen nur in der Oberklasse.

In Java steht extends. Der Konstruktor der Unterklasse ruft zuerst mit super(...) den Konstruktor der Oberklasse auf:

public class Medium {

    protected String titel;

    protected String signatur;

    public Medium(String titel, String signatur) {

        this.titel = titel;

        this.signatur = signatur;

    }

}

public class Buch extends Medium {

    private int seitenzahl;

    public Buch(String titel, String signatur, int seitenzahl) {

        super(titel, signatur);   // muss die erste Anweisung sein

        this.seitenzahl = seitenzahl;

    }

}
Üben★☆☆Nicht begonnen
Die Klasse Tier hat die Unterklassen Hund und Katze. a) Zeichnen Sie das Vererbungsdiagramm. b) Erklären Sie, was Vererbung bedeutet, und nennen Sie ein Attribut, das in…

Die Klasse Tier hat die Unterklassen Hund und Katze.

  1. a) Zeichnen Sie das Vererbungsdiagramm.
  1. b) Erklären Sie, was Vererbung bedeutet, und nennen Sie ein Attribut, das in Tier stehen sollte.
Lösen
Üben★★☆Nicht begonnen
Eine Bibliothek verwaltet Medien: Bücher (mit Seitenzahl) und DVDs (mit Spieldauer). Beide haben Titel und Signatur. a) Entwerfen Sie ein Klassendiagramm mit Oberklasse…

Eine Bibliothek verwaltet Medien: Bücher (mit Seitenzahl) und DVDs (mit Spieldauer). Beide haben Titel und Signatur.

  1. a) Entwerfen Sie ein Klassendiagramm mit Oberklasse Medium.
  1. b) Schreiben Sie die Java-Klassen Medium und Buch mit Konstruktoren (Aufruf super).
Lösen

Abstrakte Klassen und Polymorphie

Zurück zur Verkehrssimulation: Jedes Fahrzeug muss sich bewegen, aber wie, hängt vom Typ ab. In Fahrzeug lässt sich bewege() nicht sinnvoll ausprogrammieren. Man deklariert die Methode daher abstrakt: Sie hat nur einen Kopf, keinen Rumpf. Eine Klasse mit abstrakten Methoden muss als abstract deklariert werden, und von einer abstrakten Klasse kann man keine Objekte erzeugen, denn ein Objekt müsste jede Methode ausführen können.

abstract class Form {

    abstract double flaeche();      // kein Rumpf

}

class Kreis extends Form {

    double r;

    Kreis(double r) { this.r = r; }

    double flaeche() { return Math.PI * r * r; }

}

new Form() ist deshalb ein Übersetzungsfehler. Jede nicht abstrakte Unterklasse muss die abstrakten Methoden überschreiben (UML: Klassenname und abstrakte Methoden kursiv).

Polymorphie (Vielgestaltigkeit): Eine Variable vom Typ der Oberklasse darf auf Objekte jeder Unterklasse zeigen. Welche Methode läuft, entscheidet erst zur Laufzeit der tatsächliche Objekttyp. Das heißt dynamisches Binden.

Entscheidend ist die Frage, welche Methode aufgerufen wird. Im Beispiel unten ruft hallo() (in A) die Methode wer() auf:

class A { String wer(){ return "A"; }

          String hallo(){ return "Hallo " + wer(); } }

class B extends A { String wer(){ return "B"; } }

// A x = new B(); System.out.println(x.hallo());

Obwohl hallo() in A steht, läuft wer() aus B, denn das Objekt ist ein B. Ausgabe: Hallo B. Wäre wer() in A dagegen private, ist die Methode in Unterklassen nicht sichtbar, B.wer() ist dann eine ganz neue Methode und keine Überschreibung. Der Aufruf in hallo() bleibt bei A.wer(), die Ausgabe lautet daher Hallo A.

Üben★★☆Nicht begonnen
a) Erklären Sie, warum new Form() nicht erlaubt ist. b) Berechnen Sie die Summe der Flächen für Form[] f = { new Kreis(1), new Quadrat(2) }; auf zwei Nachkommastellen…
abstract class Form { abstract double flaeche(); }

class Kreis extends Form {

    double r;

    Kreis(double r){ this.r = r; }

    double flaeche(){ return Math.PI * r * r; }

}

class Quadrat extends Form {

    double a;

    Quadrat(double a){ this.a = a; }

    double flaeche(){ return a * a; }

}
  1. a) Erklären Sie, warum new Form() nicht erlaubt ist.
  1. b) Berechnen Sie die Summe der Flächen für Form[] f = { new Kreis(1), new Quadrat(2) }; auf zwei Nachkommastellen genau.
  1. c) Erläutern Sie, wo hier Polymorphie auftritt.
Lösen
Üben★★★Nicht begonnen
a) Geben Sie die Ausgabe von A x = new B(); System.out.println(x.hallo()); an und begründen Sie sie (dynamisches Binden). b) Erklären Sie, wie sich die Ausgabe ändert,…
class A { String wer(){ return "A"; } String hallo(){ return "Hallo " + wer(); } }

class B extends A { String wer(){ return "B"; } }
  1. a) Geben Sie die Ausgabe von A x = new B(); System.out.println(x.hallo()); an und begründen Sie sie (dynamisches Binden).
  1. b) Erklären Sie, wie sich die Ausgabe ändert, wenn wer() in A als private deklariert wäre, und warum B.wer() dann keine Überschreibung ist.
  1. c) Beurteilen Sie den Nutzen von Polymorphie für die Erweiterbarkeit von Software.
Lösen
Üben★★★Nicht begonnen
Ein Verkehrssimulationsprogramm für Köln soll Fahrzeuge (Auto, Bus, Fahrrad) verwalten. Jedes Fahrzeug hat Position und Geschwindigkeit und muss sich in jedem…

Ein Verkehrssimulationsprogramm für Köln soll Fahrzeuge (Auto, Bus, Fahrrad) verwalten. Jedes Fahrzeug hat Position und Geschwindigkeit und muss sich in jedem Zeitschritt bewegen; die Bewegung unterscheidet sich je Typ. Busse halten zusätzlich an Haltestellen.

  1. a) Entwerfen Sie eine Klassenhierarchie mit abstrakter Oberklasse und begründen Sie, was abstrakt ist.
  1. b) Schreiben Sie Java-Code für die abstrakte Klasse und eine Unterklasse mit der Methode bewege().
  1. c) Begründen Sie, wie Kapselung (private Attribute, Getter) Fehler in der Simulation vermeiden hilft.
Lösen

Assoziationen und Multiplizitäten

Nicht jede Beziehung ist Vererbung. Ein Kurs hat einen Lehrer und hat Schüler. Das ist eine Assoziation, in UML eine einfache Linie. An den Enden stehen die Multiplizitäten: wie viele Objekte der einen Seite zu einem Objekt der anderen gehören. Typisch sind 1, 0..1, * (beliebig viele) und 1..*.

UML-Diagramm: Schueler und Lehrer erben von Person; ein Kurs hat einen Lehrer und viele Schueler Person - name: String Lehrer - kuerzel: String Schueler - klasse: String Kurs 1 *

Die Zahl neben einer Klasse sagt, wie viele Objekte dieser Klasse zu einem Objekt der anderen Klasse gehören: Zu einem Kurs gehört genau ein Lehrer (1 neben Lehrer), zu einem Kurs gehören viele Schüler (* neben Schueler). Neben Kurs steht im Diagramm keine Multiplizität, weil hier nur diese beiden Aussagen über den Kurs gemacht werden.

Umsetzung in Java: Eine Assoziation wird zu einem Attribut der Klasse, die die andere „kennt“. Die Multiplizität 1 wird eine einzelne Referenz, * eine Sammlung (Feld oder ArrayList):

public class Kurs {

    private Lehrer lehrer;                       // Multiplizität 1

    private ArrayList<Schueler> schueler;        // Multiplizität *

    public Kurs(Lehrer lehrer) {

        this.lehrer = lehrer;

        this.schueler = new ArrayList<Schueler>();

    }

}
Üben★★☆Nicht begonnen
Ein Schulverwaltungsprogramm hat die Klassen Person (name), Schueler (klasse) und Lehrer (kuerzel). Ein Kurs hat genau einen Lehrer und viele Schüler. Ein Schüler kann…

Ein Schulverwaltungsprogramm hat die Klassen Person (name), Schueler (klasse) und Lehrer (kuerzel). Ein Kurs hat genau einen Lehrer und viele Schüler. Ein Schüler kann mehrere Kurse besuchen, und ein Lehrer kann mehrere Kurse unterrichten.

  1. a) Zeichnen Sie ein UML-Diagramm mit Vererbung und Assoziationen samt Multiplizitäten.
  1. b) Geben Sie an, wie die Assoziation Kurs–Schueler in Java als Attribut umgesetzt wird.
Lösen

Klassenbibliotheken und systematisches Testen

Niemand programmiert Listen oder Sortierverfahren jedes Mal neu. Eine Klassenbibliothek bietet fertige, getestete Klassen. Die ArrayList<T> aus java.util verwaltet eine veränderliche Folge von Objekten des Typs T:

Methode Wirkung
add(x) hängt x hinten an
get(i) liefert das Element an Position i (Zählung ab 0)
size() Anzahl der Elemente
remove(i) entfernt das Element an Position i

Vorteile der Wiederverwendung: weniger Entwicklungszeit, geprüfte Qualität, einheitliche Schnittstelle (andere Entwickler kennen sie), Pflege durch Dritte. Nachteile: Abhängigkeit, Einarbeitung, eventuell mehr Funktionalität als nötig.

Systematisch testen heißt, Testfälle nach einem Plan zu wählen, nicht beliebig. Bilden Sie Äquivalenzklassen (Eingaben, bei denen sich das Programm gleich verhält) und testen Sie zusätzlich die Grenzfälle. Zu jedem Testfall gehört das vorher festgelegte erwartete Ergebnis.

Testfall Eingabe (Noten) Erwartet
leere Liste – $-1$
ein Element 3 $3{,}0$
mehrere Elemente 1, 2, 3, 4 $2{,}5$
Extremwerte 1, 6 $3{,}5$
Üben★★★Nicht begonnen
Gegeben ist die Klassenbibliothek java.util.ArrayList<Schueler>. Die Klasse Schueler besitzt eine Methode double getNote(). a) Schreiben Sie eine Methode double…

Gegeben ist die Klassenbibliothek java.util.ArrayList<Schueler>. Die Klasse Schueler besitzt eine Methode double getNote().

  1. a) Schreiben Sie eine Methode double durchschnitt(ArrayList<Schueler> liste), die den Durchschnitt von getNote() berechnet und den Fall der leeren Liste behandelt. Begründen Sie Ihre Entscheidung für das Verhalten bei leerer Liste (z. B. Rückgabewert $0{,}0$, Double.NaN oder Auslösen einer Ausnahme).
  1. b) Erläutern Sie Vorteile der Wiederverwendung von Klassenbibliotheken.
  1. c) Beschreiben Sie, wie Sie die Methode systematisch testen (mindestens vier Testfälle mit erwarteten Ergebnissen).
Lösen

Zurück zur Verkehrssimulation: Mit einer abstrakten Oberklasse Fahrzeug, privaten Attributen mit Gettern und einer Methode bewege() pro Unterklasse bleibt die Hauptschleife unverändert, wenn neue Fahrzeugtypen dazukommen. Der Bus erhält wie der Transporter oben zusätzlich eine Liste seiner Haltestellen. Die privaten Attribute verhindern, dass anderer Code etwa die Geschwindigkeit auf einen unsinnigen Wert setzt.

Auf einen Blick

  • Klasse = Bauplan (Attribute, Methoden), Objekt = Exemplar mit eigenem Zustand. UML: Rechteck mit drei Abschnitten, - für private, + für public.

  • Kapselung: Attribute private, Zugriff über Methoden, die Werte prüfen können.

  • Vererbung (extends, ist-ein, super(...) im Konstruktor): Gemeinsames steht einmal in der Oberklasse. UML-Pfeil mit offenem Dreieck.

  • Abstrakte Klasse: mindestens eine Methode ohne Rumpf, keine Objekte erzeugbar. Unterklassen müssen die Methoden implementieren.

  • Polymorphie / dynamisches Binden: Der Objekttyp entscheidet zur Laufzeit, welche überschriebene Methode läuft. private Methoden werden nicht überschrieben.

  • Assoziation („hat ein“) wird in Java ein Attribut: Multiplizität 1 → Referenz, * → ArrayList oder Feld.

  • Klassenbibliotheken wie ArrayList sparen Aufwand. Testen mit Äquivalenzklassen, Grenzfällen und vorab berechneten Sollwerten.

  • Operatoren: erläutern Sie Begriffe an Beispielen, entwerfen Sie Diagramme, begründen Sie Entwurfsentscheidungen, beurteilen Sie Nutzen und Grenzen.

Alle Aufgaben zu diesem Abschnitt anzeigen