OOP Programmierung

Klassen

Diese Seite beschreibt abstrakte und generische Klassen in objektorientierten Programmiersprachen.

Klasse und Objekt

  • Klasse: Bauplan für Objekte. Enthält Attribute und Methoden.
  • Objekt: Konkrete Instanz einer Klasse.
// Klasse
class Hund {
    String name;

    void bellen() {
        System.out.println(name + " bellt!");
    }
}

// Objekt
Hund rex = new Hund();
rex.name = "Rex";
rex.bellen();

Abstrakte Klassen

Eine abstrakte Klasse ist wie ein Bauplan, aber kein fertiges Objekt.

Du kannst sie nicht direkt benutzen (also nicht instanziieren), aber sie dient dazu, gemeinsame Eigenschaften und Methoden für Unterklassen festzulegen.

Merkmale:

  • Du kannst keine Objekte von einer abstrakten Klasse erstellen:
  • Sie kann normale Methoden (mit Code) und abstrakte Methoden (ohne Code) enthalten.
  • Unterklassen (die erben) müssen alle abstrakten Methoden überschreiben (implementieren), sonst sind sie selbst auch abstrakt.

Warum verwendet man abstrakte Klassen?

  1. Code-Struktur und Wiederverwendbarkeit
    → Du kannst gemeinsamen Code in der abstrakten Klasse definieren (z. B. Eigenschaften wie Geschwindigkeit, Farbe …)
  2. Vorgaben machen
    → Du zwingst Unterklassen dazu, bestimmte Methoden selbst zu schreiben (z. B. starte()), damit jedes Objekt sich individuell verhält.
  3. Verhindert, dass unvollständige Objekte erstellt werden
    → z. B. ein "allgemeines Fahrzeug" ist nicht konkret genug – aber ein "Auto" oder "Motorrad" ist es.

Beispiel:

// Abstrakte Klasse (nicht direkt nutzbar)
abstract class Fahrzeug {
    int geschwindigkeit;

    // normale Methode mit Code
    void hupe() {
        System.out.println("Huuup!");
    }

    // abstrakte Methode – muss von Unterklasse umgesetzt werden
    abstract void starte();
}
// Konkrete Unterklasse
class Motorrad extends Fahrzeug {
    // Umsetzung (Implementierung) der abstrakten Methode
    void starte() {
        System.out.println("Motorrad startet");
    }
}
class Main {
    public static void main(String[] args) {
        // Fahrzeug f = new Fahrzeug(); ❌ nicht erlaubt!
        Motorrad m = new Motorrad();  // ✅ erlaubt
        m.starte();                   // Ausgabe: Motorrad startet
        m.hupe();                     // Ausgabe: Huuup!
    }
}

Vergleich zur Schnittstelle (Interface):

MerkmalAbstrakte KlasseInterface
Konstruktor?✅ Ja❌ Nein
Attribute erlaubt?✅ Ja (auch mit Logik)✅ Nur Konstanten (final static)
Methoden mit Code?✅ Ja (auch konkrete Methoden)✅ Seit Java 8 mit default
Mehrfachvererbung?❌ Nur eine Klasse erlaubt✅ Mehrere Interfaces möglich
Abstrakte Klassen sind wie eine Schablone – sie sagen, wie etwas aussehen muss, aber lassen Details offen für die Unterklassen.

Generische Klassen

Was ist das?

Generische Klassen sind flexible Baupläne, die mit verschiedenen Datentypen arbeiten können – ohne den Code mehrfach schreiben zu müssen.

Man verwendet einen Platzhalter für den Datentyp (meist T für "Type"). Erst beim Erstellen eines Objekts wird festgelegt, welcher Datentyp verwendet wird.

Warum ist das nützlich?

  1. Wiederverwendbarkeit
    → Du schreibst die Klasse nur einmal, egal ob du z. B. mit Integer, String oder Double arbeitest.
  2. Typensicherheit (Type Safety)
    → Du weißt genau, welcher Datentyp verwendet wird – das verhindert Fehler zur Laufzeit.
  3. Keine Umwandlungen nötig
    → Du musst keine Typkonvertierung (Casting) machen – der Compiler kümmert sich darum.

Beispiel: Eine generische Box

class Box<T> {
    private T inhalt;

    public void setInhalt(T inhalt) {
        this.inhalt = inhalt;
    }

    public T getInhalt() {
        return inhalt;
    }
}

Erklärung:

  • T ist ein Typparameter – ein Platzhalter für einen Datentyp.
  • Du kannst die Box später mit jedem beliebigen Typ verwenden.

Verwendung:

Box<String> stringBox = new Box<>();
stringBox.setInhalt("Hallo Welt!");
System.out.println(stringBox.getInhalt()); // Ausgabe: Hallo Welt!

Box<Integer> intBox = new Box<>();
intBox.setInhalt(42);
System.out.println(intBox.getInhalt()); // Ausgabe: 42
Hier ist T bei der ersten Box ein String, bei der zweiten ein Integer.

Vergleich ohne Generics (nicht empfohlen):

class BoxOhneGenerics {
    private Object inhalt;

    public void setInhalt(Object inhalt) {
        this.inhalt = inhalt;
    }

    public Object getInhalt() {
        return inhalt;
    }
}
BoxOhneGenerics b = new BoxOhneGenerics();
b.setInhalt("Hallo");
// später:
String text = (String) b.getInhalt(); // ❗ Manuelles Casting nötig
Nachteil: Du musst casten → Kann zu Fehlern führen, wenn der Typ nicht passt!
Generische Klassen machen deinen Code flexibler, sicherer und besser wiederverwendbar.