Skip to content
IRC-Coding IRC-Coding
Statische Methoden Instanz Attribute Klassenbeziehungen Generics UML

OOP Klassen: Statische vs Instanz-Methoden, Attribute & Beziehungen

OOP Klassen: Statische vs Instanz-Elemente, Klassenbeziehungen, Generics. UML-Beziehungen, static/instance Unterschiede und typsichere Container mit praktischen Beispielen.

S

schutzgeist

2 min read

OOP Klassen: Statische vs Instanz-Methoden, Attribute & Beziehungen

Dieser Beitrag ist eine umfassende Übersicht der OOP Klassenbestandteile – inklusive statischer vs. Instanz-Elemente, Beziehungen und Generics mit praktischen Beispielen.

In a Nutshell

Klassen bestehen aus Attributen, Methoden, Sichtbarkeiten und Verträgen. Statische Elemente betreffen die Klasse als Ganzes, Instanz-Elemente einzelne Objekte. Generics erhöhen Typsicherheit und Wiederverwendbarkeit.

Kompakte Fachbeschreibung

Eine Klasse definiert Struktur und Verhalten über Attribute, Methoden, Sichtbarkeiten, Konstruktoren, Invarianten und Verträge.

Statische vs. Instanz-Elemente:

Statische Elemente (Class-level)

  • Statische Attribute: Gehören zur Klasse, nicht zu Objekten
  • Statische Methoden: Können ohne Objekt aufgerufen werden
  • Verwendung: Zähler, Caches, Fabriken, Konstanten
  • Zugriff: Über Klassennamen, nicht über Objekt

Instanz-Elemente (Object-level)

  • Instanzattribute: Jedes Objekt hat eigene Kopie
  • Instanzmethoden: Operieren auf Objektzustand
  • Verwendung: Objektspezifische Daten und Verhalten
  • Zugriff: Nur über Objektinstanz

Klassenbeziehungen (UML):

  • Assoziation: Einfache Beziehung zwischen Klassen
  • Aggregation: “hat-ein” Beziehung mit unabhängigen Teilen
  • Komposition: “ist-Teil-von” Beziehung mit abhängigen Teilen
  • Spezialisierung: Unterklasse erbt von Basisklasse

Generics:

  • Typsicherheit: Kompilierzeit-Typprüfung
  • Wiederverwendung: Ein Code für verschiedene Typen
  • Container: List<T>, Map<K,V>, std::vector<T>

Prüfungsrelevante Stichpunkte

  • Statische Attribute: Gehören zur Klasse, gemeinsamer Wert für alle Objekte
  • Instanzattribute: Jedes Objekt hat eigene Kopie
  • Statische Methoden: Ohne Objekt aufrufbar, kein this-Zeiger
  • Instanzmethoden: Operieren auf Objektzustand mit this-Zeiger
  • Klassenbeziehungen: Assoziation, Aggregation, Komposition, Vererbung
  • UML-Notation: Verschiedene Symbole für Beziehungsarten
  • Generics: Typ-Schablonen für typsichere Container
  • IHK-relevant: Fundamentales Verständnis für OOP-Entwicklung

Kernkomponenten

  1. Statische Attribute: Klassenvariablen für gemeinsamen Zustand
  2. Instanzattribute: Objektvariablen für individuellen Zustand
  3. Statische Methoden: Klassenmethoden ohne Objektbezug
  4. Instanzmethoden: Objektmethoden mit Zustandszugriff
  5. Konstruktoren: Objektinitialisierung
  6. Beziehungen: Strukturelle Verbindungen zwischen Klassen
  7. Generics: Typ-parameterisierte Klassen und Methoden
  8. UML: Grafische Notation für Klassendesign

Praxisbeispiele

1. Statische vs Instanz Elemente in Java

public class Mitarbeiter {
    // Statische Attribute (gehören zur Klasse)
    private static int anzahlMitarbeiter = 0;
    private static final String FIRMA = "TechCorp";
    private static double mindestgehalt = 2000.0;
    
    // Instanzattribute (gehören zum Objekt)
    private int mitarbeiterId;
    private String name;
    private double gehalt;
    
    // Statischer Initialisierungsblock
    static {
        System.out.println("Mitarbeiter-Klasse wird geladen");
        anzahlMitarbeiter = 0;
    }
    
    // Konstruktor (Instanz-Initialisierung)
    public Mitarbeiter(String name, double gehalt) {
        this.mitarbeiterId = ++anzahlMitarbeiter;
        this.name = name;
        this.gehalt = Math.max(gehalt, mindestgehalt);
        
        System.out.println("Mitarbeiter " + name + " erstellt (ID: " + mitarbeiterId + ")");
    }
    
    // Statische Methode (kann ohne Objekt aufgerufen werden)
    public static int getAnzahlMitarbeiter() {
        return anzahlMitarbeiter;
    }
    
    public static String getFirma() {
        return FIRMA;
    }
    
    public static void setMindestgehalt(double mindestgehalt) {
        if (mindestgehalt > 0) {
            Mitarbeiter.mindestgehalt = mindestgehalt;
        }
    }
    
    // Instanzmethode (benötigt Objekt)
    public void erhoeheGehalt(double prozent) {
        this.gehalt *= (1 + prozent / 100);
        System.out.println(name + "s Gehalt erhöht auf " + gehalt);
    }
    
    public void anzeigen() {
        System.out.println("ID: " + mitarbeiterId + ", Name: " + name + 
                          ", Gehalt: " + gehalt + ", Firma: " + FIRMA);
    }
    
    // Getter/Setter für Instanzattribute
    public String getName() {
        return name;
    }
    
    public double getGehalt() {
        return gehalt;
    }
}

// Verwendung der Klasse
public class MitarbeiterDemo {
    public static void main(String[] args) {
        // Statische Methoden aufrufen (ohne Objekt)
        System.out.println("Anzahl Mitarbeiter: " + Mitarbeiter.getAnzahlMitarbeiter());
        System.out.println("Firma: " + Mitarbeiter.getFirma());
        
        Mitarbeiter.setMindestgehalt(2500.0);
        
        // Objekte erstellen (Instanzen)
        Mitarbeiter alice = new Mitarbeiter("Alice", 3000.0);
        Mitarbeiter bob = new Mitarbeiter("Bob", 2800.0);
        
        // Instanzmethoden aufrufen
        alice.erhoeheGehalt(5.0);
        bob.anzeigen();
        
        // Statische Methode nach Objekterstellung
        System.out.println("Anzahl Mitarbeiter: " + Mitarbeiter.getAnzahlMitarbeiter());
        
        // Fehler: this in statischer Methode nicht verfügbar
        // public static void fehlerhafteMethode() {
        //     System.out.println(this.name); // Fehler: kann nicht auf this zugreifen
        // }
    }
}

2. Klassenbeziehungen mit UML-Beispielen

// Assoziation: Dozent unterrichtet Kurse
public class Dozent {
    private String name;
    private List<Kurs> unterrichteteKurse = new ArrayList<>();
    
    public Dozent(String name) {
        this.name = name;
    }
    
    public void addKurs(Kurs kurs) {
        unterrichteteKurse.add(kurs);
        kurs.setDozent(this); // Rückreferenz
    }
    
    public void zeigeKurse() {
        System.out.println(name + " unterrichtet:");
        for (Kurs kurs : unterrichteteKurse) {
            System.out.println("  - " + kurs.getTitel());
        }
    }
}

public class Kurs {
    private String titel;
    private Dozent dozent; // Rückreferenz
    
    public Kurs(String titel) {
        this.titel = titel;
    }
    
    public void setDozent(Dozent dozent) {
        this.dozent = dozent;
    }
    
    public String getTitel() {
        return titel;
    }
}

// Aggregation: Abteilung hat Mitarbeiter (können existieren ohne Abteilung)
public class Abteilung {
    private String name;
    private List<Mitarbeiter> mitarbeiter = new ArrayList<>();
    
    public Abteilung(String name) {
        this.name = name;
    }
    
    public void addMitarbeiter(Mitarbeiter mitarbeiter) {
        this.mitarbeiter.add(mitarbeiter);
    }
    
    public void removeMitarbeiter(Mitarbeiter mitarbeiter) {
        this.mitarbeiter.remove(mitarbeiter);
        // Mitarbeiter existiert weiter
    }
}

// Komposition: Bestellung hat Bestellpositionen (existieren nur mit Bestellung)
public class Bestellung {
    private String bestellId;
    private List<Bestellposition> positionen = new ArrayList<>();
    
    public Bestellung(String bestellId) {
        this.bestellId = bestellId;
    }
    
    public void addPosition(String produkt, int menge, double preis) {
        Bestellposition position = new Bestellposition(produkt, menge, preis);
        positionen.add(position);
    }
    
    public double berechneGesamtbetrag() {
        return positionen.stream()
            .mapToDouble(Bestellposition::getGesamtpreis)
            .sum();
    }
    
    // Innere Klasse für Komposition
    private class Bestellposition {
        private String produkt;
        private int menge;
        private double einzelpreis;
        
        public Bestellposition(String produkt, int menge, double einzelpreis) {
            this.produkt = produkt;
            this.menge = menge;
            this.einzelpreis = einzelpreis;
        }
        
        public double getGesamtpreis() {
            return menge * einzelpreis;
        }
    }
}

3. Generics mit statischen Elementen

// Generische Klasse mit statischen Elementen
public class Container<T> {
    // Statische Attribute (sind nicht generisch!)
    private static int anzahlContainer = 0;
    private static final String VERSION = "1.0";
    
    // Instanzattribute (sind generisch)
    private T inhalt;
    private int id;
    
    public Container(T inhalt) {
        this.inhalt = inhalt;
        this.id = ++anzahlContainer;
    }
    
    // Statische Methode (kann nicht auf T zugreifen)
    public static int getAnzahlContainer() {
        return anzahlContainer;
    }
    
    public static String getVersion() {
        return VERSION;
    }
    
    // Instanzmethode (kann auf T zugreifen)
    public T getInhalt() {
        return inhalt;
    }
    
    public void setInhalt(T inhalt) {
        this.inhalt = inhalt;
    }
    
    public void anzeigen() {
        System.out.println("Container #" + id + ": " + 
                          (inhalt != null ? inhalt.toString() : "leer"));
    }
    
    // Generische Methode (statisch)
    public static <U> Container<U> create(U inhalt) {
        return new Container<>(inhalt);
    }
}

// Verwendung
public class ContainerDemo {
    public static void main(String[] args) {
        // Statische Methoden aufrufen
        System.out.println("Container-Version: " + Container.getVersion());
        
        // Verschiedene Container-Typen
        Container<String> stringContainer = new Container<>("Hallo");
        Container<Integer> intContainer = new Container<>(42);
        Container<Double> doubleContainer = Container.create(3.14);
        
        stringContainer.anzeigen();
        intContainer.anzeigen();
        doubleContainer.anzeigen();
        
        System.out.println("Anzahl Container: " + Container.getAnzahlContainer());
        
        // Fehler: Statische Attribute sind nicht generisch
        // Container<String>.getAnzahlContainer(); // Syntax-Fehler
    }
}

4. Factory Pattern mit statischen Methoden

public class FahrzeugFactory {
    // Statische Factory-Methoden
    public static Fahrzeug erstellePKW(String marke, int leistung) {
        return new PKW(marke, leistung, 4);
    }
    
    public static Fahrzeug erstelleMotorrad(String marke, int leistung) {
        return new Motorrad(marke, leistung, false);
    }
    
    public static Fahrzeug erstelleLKW(String marke, int leistung, double ladung) {
        return new LKW(marke, leistung, ladung);
    }
    
    // Statische Methode mit Validierung
    public static Fahrzeug erstelleFahrzeug(String typ, String marke, int leistung) {
        switch (typ.toLowerCase()) {
            case "pkw":
                return erstellePKW(marke, leistung);
            case "motorrad":
                return erstelleMotorrad(marke, leistung);
            case "lkw":
                return erstelleLKW(marke, leistung, 1000.0);
            default:
                throw new IllegalArgumentException("Unbekannter Fahrzeugtyp: " + typ);
        }
    }
}

// Abstrakte Basisklasse
abstract class Fahrzeug {
    protected String marke;
    protected int leistung;
    
    public Fahrzeug(String marke, int leistung) {
        this.marke = marke;
        this.leistung = leistung;
    }
    
    public abstract void anzeigen();
}

// Konkrete Klassen
class PKW extends Fahrzeug {
    private int anzahlTueren;
    
    public PKW(String marke, int leistung, int anzahlTueren) {
        super(marke, leistung);
        this.anzahlTueren = anzahlTueren;
    }
    
    @Override
    public void anzeigen() {
        System.out.println("PKW: " + marke + ", " + leistung + " PS, " + anzahlTueren + " Türen");
    }
}

class Motorrad extends Fahrzeug {
    private boolean hatSeitenwagen;
    
    public Motorrad(String marke, int leistung, boolean hatSeitenwagen) {
        super(marke, leistung);
        this.hatSeitenwagen = hatSeitenwagen;
    }
    
    @Override
    public void anzeigen() {
        System.out.println("Motorrad: " + marke + ", " + leistung + " PS, " + 
                          (hatSeitenwagen ? "mit" : "ohne") + " Seitenwagen");
    }
}

class LKW extends Fahrzeug {
    private double ladung;
    
    public LKW(String marke, int leistung, double ladung) {
        super(marke, leistung);
        this.ladung = ladung;
    }
    
    @Override
    public void anzeigen() {
        System.out.println("LKW: " + marke + ", " + leistung + " PS, " + ladung + " kg Ladung");
    }
}

// Verwendung der Factory
public class FactoryDemo {
    public static void main(String[] args) {
        // Statische Factory-Methoden verwenden
        Fahrzeug golf = FahrzeugFactory.erstellePKW("Volkswagen", 110);
        Fahrzeug harley = FahrzeugFactory.erstelleMotorrad("Harley", 80);
        Fahrzeug scania = FahrzeugFactory.erstelleLKW("Scania", 500, 20000.0);
        
        golf.anzeigen();
        harley.anzeigen();
        scania.anzeigen();
        
        // Dynamische Erstellung
        Fahrzeug bmw = FahrzeugFactory.erstelleFahrzeug("pkw", "BMW", 150);
        bmw.anzeigen();
    }
}

UML-Notation für Klassenbestandteile

Klasse mit statischen und Instanz-Elementen

+---------------------------+
|        Mitarbeiter         |
+---------------------------+
| - anzahlMitarbeiter: int  |  <<static>>
| - FIRMA: String          |  <<static>>
| - mitarbeiterId: int     |
| - name: String           |
| - gehalt: double         |
+---------------------------+
| + getAnzahlMitarbeiter(): int | <<static>>
| + setMindestgehalt(double): void | <<static>>
| + erhoeheGehalt(double): void    |
| + anzeigen(): void              |
+---------------------------+

Beziehungen in UML

Dozent 1..* --* Kurs           (Assoziation)
Abteilung 1 --o* Mitarbeiter    (Aggregation)
Bestellung 1 --* Bestellposition (Komposition)
Fahrzeug <|-- PKW               (Vererbung)

Statische vs. Instanz - Entscheidungshilfe

Wann statische Elemente verwenden?

Statische Attribute:

  • Zähler für alle Instanzen
  • Konstanten für die gesamte Klasse
  • Gemeinsame Ressourcen (Datenbank-Verbindung)
  • Caches für die Klasse

Statische Methoden:

  • Factory-Methoden zur Objekterstellung
  • Utility-Methoden ohne Zustand
  • Konvertierungsmethoden
  • Validierungsmethoden

Wann Instanz-Elemente verwenden?

Instanzattribute:

  • Objektspezifische Daten
  • Zustand, der sich ändert
  • Konfiguration pro Objekt

Instanzmethoden:

  • Methoden, die auf Objektzustand zugreifen
  • Verhalten, das von Instanzdaten abhängt
  • Methoden, die this-Zeiger benötigen

Vorteile und Nachteile

Vorteile von statischen Elementen

  • Speichereffizienz: Nur eine Kopie für alle Objekte
  • Einfacher Zugriff: Ohne Objektinstanz aufrufbar
  • Gemeinsamer Zustand: Für alle Objekte gleich
  • Factory-Pattern: Einfache Objekterstellung

Nachteile

  • Globale Zustände: Erschwert Testbarkeit
  • Thread-Safety: Bei parallelem Zugriff
  • Flexibilität: Keine Polymorphie möglich
  • Initialisierung: Komplexe Abhängigkeiten

Häufige Prüfungsfragen

  1. Was ist der Unterschied zwischen statischen und Instanz-Attributen? Statische Attribute gehören zur Klasse (eine Kopie), Instanzattribute zum Objekt (pro Objekt eine Kopie).

  2. Können statische Methoden auf Instanzattribute zugreifen? Nein, da sie kein this-Zeiger haben und nicht wissen, zu welchem Objekt sie gehören.

  3. Erklären Sie die Aggregation vs Komposition! Aggregation: Teile können ohne Ganzes existieren, Komposition: Teile existieren nur mit Ganzem.

  4. Warum sind statische Attribute nicht generisch? Sie gehören zur Klasse, nicht zur Instanz, daher gibt es nur eine Version pro Klasse.

Wichtigste Quellen

  1. https://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html
  2. https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/static-classes-and-static-class-members
  3. https://www.uml-diagrams.org/class-diagrams.html
Zurück zum Blog
Share:

Ähnliche Beiträge