Jetzt anmelden...

Login
Passwort
Registrieren

Java Tutorial #14

Java Initializer

Vielleicht werden Sie Initializer nur selten in Programmcodes finden und Sie sollten sie auch sparsam einsetzen, da sie den Code unübersichtlich machen können. Trotzdem sind sie ein Konzept, das wir für einen umfassenden Umgang mit der Objektorientierung beherrschen sollten.

Kommentare [0]

Stefan 10.11.2018

Infos zum Artikel

Kategorie Java
Autor Stefan
Datum 10.11.2018

Thema in Kurzform

  • Initializer sind spezielle Methoden ohne Methodenkopf.
  • Der Code von Instanz-Initializern wird unmitelbar bei der Objekt-Erzeugung aufgerufen.
  • static-Initializer werden mit dem Schlüsselwort static eingeleitet und werden bei der ersten Benutzung der Klasse automatisch aufgerufen.

Instanz-Initializer

Dass die Anweisungen von Konstruktoren und Methoden immer zwischen zwei geschweiften Klammern { // Code } stehen, ist uns längst schon klar. Auch der Code von Initializern steht innerhalb eines Paars geschweifter Klammern. Aber: Es gibt bei Initializern keinen "Kopf", der vor dem Code-Block steht. Auch ein spezielles einleitendes Schlüsselwort (wie if, switch, while usw.) gibt es nicht.

Initializer sehen also wie anonyme Methoden aus:

public class Cat {

    { System.out.println("Ich bin der Initializer!"); }
}

Diese Art von Initializer werden bei der Objekterzeugung automatisch ausgeführt, weshalb sie "Instanz"-Initialzer heißen. Das Besondere: Die Ausführung geschieht noch vor dem Konstruktor-Aufruf:

public class Cat {

    public Cat(){
        System.out.println("Ich bin der Konstruktor");
    }

    { System.out.println("Ich bin der Initializer!"); }

    public static void main(String[] main){
        Cat c = new Cat(); // Cat-Objekt erzeugen
    }
}
Cat.java

Da zuerst der Instanz-Initializer und danach der Konstruktor ausgeführt wird, lautet der Output auf der Konsole so:

Ich bin der Initializer!
Ich bin der Konstruktor

Es gibt einige Regeln für Instanz-Initializer bei der Objekterzeugung:

  • Initializer werden vor den Konstruktoren der Klasse ausgeführt
  • Es kann mehrere Initializer geben.
  • Initializer stehen üblicherweise oben im Klassencode, was aber keine Pflicht ist.
  • Bei der Objekterzeugung werden die Initializer in der Reihenfolge ausgeführt, in der sie geschrieben stehen.
  • Nicht vergessen: Instanzvariablen haben den gleichen Stellenwert wie Instanz-Initializer. Sie werden gemeinsam mit diesen (entsprechend ihrer Reihenfolge) initialisiert.

Alles verstanden? Dann sagen Sie mal, was der folgende Code ausgibt:

public class Cat {

    private String name = "Simba";

     public Cat(){
        name = "Bailey";
        System.out.println("Cats are liquid");
    }

    public static void main(String[] main){
        Cat c = new Cat();
        System.out.println(c.name);
    }

    { System.out.println("Cats are jerks"); }
}

Dieser Code printed:

Cats are jerks
Cats are liquid
Bailey

Klar warum? 😀 Zuerst wird innerhalb der Main-Methode ein neues Cat-Objekt erzeugt. Das hat zur Folge, dass die Instanzvariable name mit dem String "Simba" initialisiert und sofort darauf der Instanz-Initializer in Zeile 15 aufgerufen wird, der Cats are jerks printed. Erst danach wird in Zeile 5 der Konstruktor der Klasse aufgerufen. Dieser ändert den Wert von name in Bailey und printed den Text Cats are liquid auf der Konsole. Damit ist das neue Cat-Objekt fertig erstellt. Zu guter Letzt wird noch der letzte Wert von name auf der Konsole ausgegeben.

static-Initializer

Wenn Sie anfangs noch überrascht waren, dass es mit Instanz-Initializern Code gibt, der noch vor dem Konstruktor ausgeführt wird, dann passen Sie gut auf, denn es geht noch mehr: Mit dem static-Initializer können wir einen Code-Block sogar noch eine Stufe früher ausführen.

Static-Initializer werden gebildet wie Instanz-Initializer aber mit dem öffnenden Schlüsselwort static. Sehen wir uns hierzu einmal die Klasse StaticCat an:

public class StaticCat {

    public StaticCat(){
        System.out.println("Ich bin der Konstruktor");
    }

    { System.out.println("Ich bin ein Instanz-Initializer."); }

    static{
      System.out.println("Ich bin der static-Initializer!"); }

    public static void main(String[] main){
        StaticCat sc = new StaticCat();
    }
}

Ausgabe:

Ich bin der static-Initializer!
Ich bin ein Instanz-Initializer.
Ich bin der Konstruktor

Die Sache läuft so ab: Noch bevor es ein StaticCat-Objekt gibt, quasi bei der ersten Benutzung der Klasse(!), wird der static-Initializer ausgeführt.

Wir hätten uns die Objekterzeugung in Zeile 13 also auch sparen können: Der Static-Initializer wird trotzdem ausgeführt. Wir haben den Instanz-Initializer und Konstruktor nur eingebaut, um die Reihenfolge der Code-Ausführung zu zeigen.

Da der static-Initialzer (von dem es auch mehrere in einer Klasse geben kann) somit von der Klasse abhängt, kann er auch als "Klassen-Initializer" bezeichnet werden. Static-Initializer werden auch nur ein einziges Mal ausgeführt.

Static-Initializer wurden speziell für die Initialisierung von statischen Klassenvariablen und Konstanten erfunden:

public class StaticCat {

   public static final String NAME;

    static{
        NAME = "Hero";
    }
}

Fällt Ihnen an diesem Code irgendetwas auf? Richtig: "Eigentlich" müssen Konstanten wie NAME sofort initialisiert werden, ansonsten gibt es einen Compiler-Fehler. Tatsächlich geschieht dies hier auch (die Regel gilt also weiterhin), wenngleich nicht in derselben Anweisung. Der Grund: Der static-Initializer ist der erste Code, der überhaupt ausgeführt wird und damit geht die Sache hier in Ordnung! 😎

Wie bei statischen Methoden gilt auch bei statischen Initializern, dass sie niemals auf Instanz-Elemente (Instanzvariablen, Instanz-Methoden) zugreifen können. Der folgende Code produziert darum ein Paar Compiler-Fehler:

public class StaticCat {

  private int alter = 12;

  public int getAlter(){
      return alter;
  }

    static{
        System.out.println(alter); // Fehler 1
        getAlter(); // Fehler 2
    }
}

In Zeile 10 versucht der static-Initializer auf die Instanzvariable alter und in Zeile 11 auf die Instanz-Methode getAlter() zuzugreifen. Da der statische Initializer aber objektunabhängig ist, kann dies nicht funktionieren, da alter und getAlter() an die Existenz eines Objekts gebunden sind. Mit einem Instanz-Initializer andererseits würde dieser Code einwandfrei funktionieren.

Übungen

einfach

Was ist der Unterschied zwischen einem Instanz-Initializer und einem static-Initializer?

Lösung ein-/ausblenden

mittel

Was gibt der folgende Code auf der Konsole aus?

ppublic class Uebung {

    private String a = "Programming";
    private static String b = "Java";
    private String c = "Code";

    public Uebung(){
        System.out.println(a);
    }

    static{
        System.out.println(b);
    }

    {
        System.out.println(c);
    }

    public static void main(String[] args){
        new Uebung();
        new Uebung();
    }
}

Lösung ein-/ausblenden

schwer

Was wird auf der Konsole ausgegeben?

public class Diamond {

    public static int solution;

    public Diamond(){
        solution++;
    }

    { solution += 4; }

    static
    { solution += 2; }
    { solution -= 3; }

}
public class DiamondEngage {

    public static void main(String[] args){
        System.out.print(Diamond.solution);
        System.out.print(Diamond.solution);
        new Diamond();
        new Diamond();
        new Diamond();
        System.out.print(Diamond.solution);

    }
}

A. Der Code ist fehlerhaft!
B. 123
C. 228
D. -1-114
E. 004

Lösung ein-/ausblenden

Kommentar schreiben

Nur angemeldete und aktivierte Benutzer können kommentieren.

Alle Kommentare

Es gibt bislang noch keine Kommentare zu diesem Thema.

Objektinteraktion

Wie interagieren Objekte in einem Programm miteinander?

Scope von Variablen

Wie lange lebt eine Variable eigentlich?

Methoden in Java

Wie erstelle ich Methoden?

FALCONBYTE.NET

Handmade with 🖤️

© 2018, 2019 Stefan E. Heller

Impressum | Datenschutz

facebook programmieren lernen twitter programmieren lernen youtube programmieren lernen