Skip to content
IRC-Coding IRC-Coding
Static Methods Instance Attributes Class Relationships Generics UML

OOP Classes: Static vs Instance Methods & Attributes

Master OOP classes: static vs instance elements, class relationships, generics, UML diagrams, and type-safe containers with practical examples.

S

schutzgeist

2 min read
OOP Classes: Static vs Instance Methods & Attributes

OOP Classes: Static vs Instance Methods, Attributes & Relationships

This article is a comprehensive overview of OOP class components – including static vs. instance elements, relationships and generics with practical examples.

In a Nutshell

Classes consist of attributes, methods, visibility levels and contracts. Static elements concern the class as a whole, instance elements individual objects. Generics increase type safety and reusability.

Compact Technical Description

A class defines structure and behavior through attributes, methods, visibility levels, constructors, invariants and contracts.

Static vs. Instance Elements:

Static Elements (Class-level)

  • Static Attributes: Belong to the class, not to objects
  • Static Methods: Can be called without an object
  • Usage: Counters, caches, factories, constants
  • Access: Via class name, not via object

Instance Elements (Object-level)

  • Instance Attributes: Each object has its own copy
  • Instance Methods: Operate on object state
  • Usage: Object-specific data and behavior
  • Access: Only via object instance

Class Relationships (UML):

  • Association: Simple relationship between classes
  • Aggregation: “has-a” relationship with independent parts
  • Composition: “is-part-of” relationship with dependent parts
  • Specialization: Subclass inherits from base class

Generics:

  • Type Safety: Compile-time type checking
  • Reusability: One code for different types
  • Containers: List<T>, Map<K,V>, std::vector<T>

Exam-Relevant Key Points

  • Static Attributes: Belong to the class, shared value for all objects
  • Instance Attributes: Each object has its own copy
  • Static Methods: Callable without object, no this pointer
  • Instance Methods: Operate on object state with this pointer
  • Class Relationships: Association, aggregation, composition, inheritance
  • UML Notation: Different symbols for relationship types
  • Generics: Type templates for type-safe containers
  • IHK-relevant: Fundamental understanding for OOP development

Core Components

  1. Static Attributes: Class variables for shared state
  2. Instance Attributes: Object variables for individual state
  3. Static Methods: Class methods without object reference
  4. Instance Methods: Object methods with state access
  5. Constructors: Object initialization
  6. Relationships: Structural connections between classes
  7. Generics: Type-parameterized classes and methods
  8. UML: Graphical notation for class design

Practical Examples

1. Static vs Instance Elements 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. Class Relationships with UML Examples

// Association: Instructor teaches courses
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); // Back reference
    }
    
    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; // Back reference
    
    public Kurs(String titel) {
        this.titel = titel;
    }
    
    public void setDozent(Dozent dozent) {
        this.dozent = dozent;
    }
    
    public String getTitel() {
        return titel;
    }
}

// Aggregation: Department has employees (can exist without department)
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);
        // Employee continues to exist
    }
}

// Composition: Order has order items (only exist with order)
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();
    }
    
    // Inner class for composition
    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 with Static Elements

// 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 with Static Methods

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 for Class Components

Class with Static and Instance Elements

+---------------------------+
|        Employee            |
+---------------------------+
| - numberOfEmployees: int  |  <<static>>
| - COMPANY: String        |  <<static>>
| - employeeId: int        |
| - name: String           |
| - salary: double         |
+---------------------------+
| + getNumberOfEmployees(): int | <<static>>
| + setMinimumSalary(double): void | <<static>>
| + increaseSalary(double): void    |
| + display(): void                |
+---------------------------+

Relationships in UML

Instructor 1..* --* Course          (Association)
Department 1 --o* Employee          (Aggregation)
Order 1 --* OrderPosition           (Composition)
Vehicle <|-- Car                    (Inheritance)

Static vs. Instance - Decision Aid

When to Use Static Elements?

Static Attributes:

  • Counters for all instances
  • Constants for the entire class
  • Shared resources (database connection)
  • Class-level caches

Static Methods:

  • Factory methods for object creation
  • Utility methods without state
  • Conversion methods
  • Validation methods

When to Use Instance Elements?

Instance Attributes:

  • Object-specific data
  • State that changes
  • Configuration per object

Instance Methods:

  • Methods that access object state
  • Behavior that depends on instance data
  • Methods that require the this pointer

Advantages and Disadvantages

Advantages of Static Elements

  • Memory Efficiency: Only one copy for all objects
  • Simple Access: Callable without object instance
  • Shared State: Equal for all objects
  • Factory Pattern: Easy object creation

Disadvantages

  • Global State: Complicates testability
  • Thread Safety: With concurrent access
  • Flexibility: No polymorphism possible
  • Initialization: Complex dependencies

Common Exam Questions

  1. What is the difference between static and instance attributes? Static attributes belong to the class (one copy), instance attributes belong to the object (one copy per object).

  2. Can static methods access instance attributes? No, because they have no this pointer and don’t know which object they belong to.

  3. Explain aggregation vs composition! Aggregation: Parts can exist without the whole, composition: Parts exist only with the whole.

  4. Why are static attributes not generic? They belong to the class, not the instance, so there is only one version per class.

Most Important Sources

  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
Back to Blog
Share:

Related Posts