RU | EN | DE

static

Zweck: Ermöglicht den Zugriff auf ein Feld oder eine Methode ohne Erstellung eines Objekt der Klasse. Gehört zur Klasse selbst und nicht zu einem spezifischen Instanz.

Anwendung:

  • Globale Konstanten (static final)
  • Hilfsmethoden (Math.max, Collections.sort)
  • Zähler und Factory-Methoden

Beispiel:

class Counter {
  static int count = 0; // gemeinsam für alle Objekte
  public Counter() { count++; }
}
Counter c1 = new Counter();
Counter c2 = new Counter();
System.out.println(Counter.count); // 2

💡 Besonderheiten:

  • static Variablen werden einmal beim Klassenladen erstellt.
  • Auf this oder super kann in einer static Methode nicht zugegriffen werden.
  • Wird oft für Singleton und Utility Klassen verwendet.

final

Zweck: Fixiert einen Wert oder verhindert Änderungen des Verhaltens.

Anwendung:

  • Variable → kann nicht neu definiert werden.
  • Methode → kann nicht in Subklassen neu definiert werden.
  • Klasse → kann nicht abgeleitet werden.

Beispiele:

final int MAX = 10; // Konstante
// MAX = 15; // Fehler
final class Utils {} // kann nicht abgeleitet werden
class Parent {
  final void greet() { System.out.println("Hi"); }
}
class Child extends Parent {
  // void greet() {} // Fehler — Methode final
}

💡 Tipp: final wird oft mit static kombiniert → public static final = Konstante (z.B. Math.PI).

this

Zweck: Referenz auf das aktuelle Objekt – wird innerhalb von Methoden oder Konstruktoren verwendet.

Beispiel:

class Person {
  private String name;
  public Person(String name) {
  this.name = name; // "this" unterscheidet das Feld vom Parameter
  }
  public void print() {
  System.out.println(this.name);
  }
}

💡 Besonderheiten:

  • this() kann verwendet werden, um einen anderen Konstruktor in derselben Klasse aufzurufen:
public Person() {
  this("Default");
}
  • Auf this kann in static Methoden nicht zugegriffen werden (da kein Objekt vorhanden ist).

super

Zweck: Wird verwendet, um auf Methoden und Konstruktoren der Elternklasse zuzugreifen.

Beispiel:

class Animal {
  void speak() { System.out.println("Animal speaks"); }
}
class Dog extends Animal {
  void speak() {
  super.speak(); // Aufruf der Methode der Elternklasse
  System.out.println("Dog barks");
  }
}

💡 Besonderheiten:

  • super() muss die erste Zeile im Konstruktor sein.
  • Hilft bei der Überschreibung von Methoden und bei der Initialisierung von Subklassen.

volatile

Zweck: Wird für Variablen verwendet, die von mehreren Threads zugänglich sind. Garantiert, dass alle Threads den aktuellen Wert aus dem Speicher lesen und nicht aus dem Cache der Prozessor.

Beispiel:

class FlagExample {
  private volatile boolean running = true;
  void stop() {
  running = false;
  }
  void run() {
  while (running) {
  }
  }
}

💡 Ohne volatile kann ein anderer Thread die Änderung der Variablen nicht sehen, da sie möglicherweise im CPU-Cache gespeichert ist. 📍 Verwende volatile, wenn die Variable nicht vom vorherigen Zustand abhängt (z.B. ein boolean-Flag).

transient

Zweck: Gibt an, dass ein Feld nicht serialisiert werden muss. Beim Speichern eines Objekts (z.B. in einer Datei oder über ein Netzwerk) wird dieses Feld übersprungen.

Beispiel:

class User implements Serializable {
  private String username;
  private transient String password; // wird nicht serialisiert
}

💡 Das Feld transient wird nach der Deserialisierung zu null oder 0. 📍 Wird bei der Arbeit mit Serializable und Sicherheit (Passwörter, Schlüssel) verwendet.

Unterschied zwischen == und .equals()

VergleichWas tut es?Wo wird es verwendet?
==Vergleicht Referenzen (Adressen im Speicher)Objekte, Primitive
.equals()Vergleicht den InhaltWird in Klassen überschrieben (String, Integer, etc.)
Beispiel:
String a = new String("hello");
String b = new String("hello");
 
System.out.println(a == b);  // false (verschiedene Objekte)
System.out.println(a.equals(b)); // true  (gleicher Inhalt)

💡 Für Primitive vergleicht == die Werte, für Objekte die Referenzen. 📍 Tipp:

  • Bei Strings, Collections und Objekten sollte immer .equals() verwendet werden.
  • Überschreibe .equals() immer zusammen mit hashCode().

String, StringBuilder, StringBuffer

String

  • Unveränderliches (immutable) Objekt.
  • Jede Konkatenationsoperation erzeugt ein neues Objekt im Speicher.
String s = "Hello";
s += " World"; // ein neues Objekt wird erstellt

📍 Wird verwendet, wenn sich die Zeichenkette nicht oft ändert. ⚠️ Vermeide die Konkatenation von String in einer Schleife – es wird viel Garbage für den GC erzeugt.

StringBuilder

  • Veränderliches (mutable).
  • Nicht synchronisiert → schneller, aber nicht thread-sicher.
StringBuilder sb = new StringBuilder("Hello");
sb.append(" World");
System.out.println(sb); // Hello World

📍 Wird in Single-Thread-Operationen verwendet.

StringBuffer

  • Fast das Gleiche wie StringBuilder, aber synchronisiert (thread-sicher).
  • Etwas langsamer.
StringBuffer sb = new StringBuffer("Hi");
sb.append(" there");
System.out.println(sb);

📍 Wird in einer Multi-Thread-Umgebung verwendet, wenn Strings gleichzeitig von verschiedenen Threads bearbeitet werden.

🧩 Vergleich

KlasseVeränderlichkeitThread-SicherheitGeschwindigkeitWann verwenden?
Stringimmutable✅ sicher🐢 langsam bei häufigen ÄnderungenStatische Texte, Schlüssel
StringBuilder✅ veränderlich❌ nicht⚡ schnellGenerierung von Strings, Muster
StringBuffer✅ veränderlich✅ ja⚖️ mittelBei Multi-Threading

⚙️ Best Practices

  • ✅ Verwende StringBuilder für Konkatenationen in Schleifen.
  • ✅ Vergleiche Strings immer mit .equals() und nicht mit ==.
  • ✅ Mache Konstanten mit public static final.
  • ✅ Verwende volatile nur bei Bedarf für Synchronisierung.
  • ✅ Denk daran: transient schützt Daten bei der Serialisierung.
  • ✅ Missbrauche static nicht – es reduziert die Testbarkeit.