W3docs

Java this-Schlüsselwort

Das this-Schlüsselwort in Java: Felder disambiguieren, Konstruktoren verketten und Methoden aufrufen.

Innerhalb einer Instanzmethode oder eines Konstruktors verweist this auf das Objekt, auf dem die Methode aufgerufen wird. Es ist ein impliziter Parameter, den die JVM für Sie übergibt. Meistens muss man es nicht explizit erwähnen — bloße Namen werden bereits über this aufgelöst — aber es gibt einige Situationen, in denen man es explizit schreiben muss. Dieses Kapitel behandelt diese Fälle.

Was this ist

Wenn Sie dog.bark() aufrufen, übergibt die JVM dog heimlich als erstes Argument. Innerhalb von bark heißt dieses Argument this. Also:

public class Dog {
  String name;
  void bark() {
    System.out.println(this.name + " says woof");   // this == dog
  }
}

Dog rex = new Dog();
rex.name = "Rex";
rex.bark();    // inside, this == rex

Sie können this. weglassen und einfach name schreiben — Java sucht den bloßen Bezeichner im aktuellen Gültigkeitsbereich, findet keine lokale Variable mit diesem Namen, geht dann zu den Instanzfeldern, findet name und löst es als this.name auf. Beide Formen werden zum gleichen Bytecode kompiliert.

Verwendung 1 — Einen Parameter von einem Feld disambiguieren

Der häufigste Grund, this. explizit zu schreiben, ist, wenn ein Parameter oder eine lokale Variable denselben Namen wie ein Feld hat:

public class Point {
  int x, y;
  public Point(int x, int y) {
    this.x = x;        // field = parameter
    this.y = y;
  }
}

Ohne this. würde x = x; den Parameter sich selbst zuweisen und das Feld bei 0 belassen. Der Compiler warnt nicht — es ist eine gültige Anweisung — daher ist dies ein verbreiteter stiller Fehler.

Man könnte die Parameter umbenennen (int newX, int newY), um die Kollision zu vermeiden, aber Parameternamen an Feldnamen anzupassen ist bei Weitem die lesbarere Konvention, weshalb das this.-Muster überall in Java-Code vorkommt.

Verwendung 2 — Das aktuelle Objekt übergeben

Manchmal muss eine Methode this als Argument an eine andere Methode oder einen Konstruktor übergeben:

public class Order {
  List<Item> items = new ArrayList<>();
  void register(Tracker t) {
    t.watch(this);          // pass myself to the tracker
  }
}

Es gibt keine andere Möglichkeit, auf das aktuelle Objekt als Wert zu verweisen, daher ist this hier erforderlich.

Eine häufige Variante ist ein Fluent Builder, bei dem jeder Setter this zurückgibt, sodass Aufrufe verkettet werden können:

public class Url {
  String scheme, host, path;
  public Url scheme(String s) { this.scheme = s; return this; }
  public Url host(String h)   { this.host   = h; return this; }
  public Url path(String p)   { this.path   = p; return this; }
}

Url u = new Url().scheme("https").host("w3docs.com").path("/learn-java");

Verwendung 3 — this(...) zum Aufrufen eines anderen Konstruktors

Innerhalb eines Konstruktors ruft this(args) einen anderen Konstruktor derselben Klasse auf — siehe Konstruktoren. Es muss die erste Anweisung sein, und ein Konstruktor kann nur an einen anderen delegieren:

public Rectangle()                  { this(1, 1); }
public Rectangle(double side)       { this(side, side); }
public Rectangle(double w, double h){ this.width = w; this.height = h; }

Dies unterscheidet sich vom this.-Qualifizierer — this(...) mit Argumenten ist die Konstruktoraufruf-Form; this.foo (oder einfach this allein) ist die Referenzform.

Wann this unzulässig ist

this existiert nur in Instanz-Kontexten. In einer static-Methode oder einem statischen Initialisierer gibt es kein aktuelles Objekt, daher ist das Schreiben von this ein Kompilierfehler:

public class Counter {
  static int total;
  static void reset() {
    this.total = 0;     // ERROR: cannot use this in a static context
  }
}

main ist static, weshalb man nicht direkt auf Instanzfelder darin verweisen kann — man muss zuerst ein Objekt erstellen.

this vs. impliziter Feldzugriff

Wenn es keine Namenskollision gibt, ist this. rein stilistisch:

double area()      { return Math.PI * radius * radius; }
double areaThisly(){ return Math.PI * this.radius * this.radius; }

Beide funktionieren. Die implizite Form ist häufiger; manche Codebasen verwenden this. überall aus Konsistenzgründen oder um den Empfänger auf einen Blick sichtbar zu machen. Beides ist in Ordnung — wählen Sie eines und wenden Sie es in einer Datei konsequent an.

Innere Klassen und das äußere this

Eine nicht-statische innere Klasse hat einen impliziten Verweis auf ihre umschließende Instanz. Aus der inneren Klasse heraus verweist this auf das innere Objekt; die äußere Instanz ist Outer.this:

public class Outer {
  int x = 1;
  class Inner {
    int x = 2;
    void demo() {
      System.out.println(this.x);          // 2  — Inner's x
      System.out.println(Outer.this.x);    // 1  — Outer's x
    }
  }
}

Dies tritt nur in Szenarien mit verschachtelten Klassen auf, die in verschachtelten Klassen und den folgenden Kapiteln behandelt werden.

Lambdas vs. anonyme Klassen

Ein Lambda führt kein neues this ein. Innerhalb eines Lambdas ist this die umschließende Instanz — dasselbe Objekt, auf dem die umgebende Methode läuft. Eine anonyme Klasse hingegen ist ihr eigenes Objekt, daher verweist this darin auf diese anonyme Instanz:

public class Demo {
  String label = "outer";
  void run() {
    Runnable lambda = () -> System.out.println(this.label);   // "outer"
    Runnable anon = new Runnable() {
      String label = "inner";
      public void run() { System.out.println(this.label); }   // "inner"
    };
    lambda.run();   // prints outer
    anon.run();     // prints inner
  }
}

Dies ist einer der wenigen Verhaltensunterschiede zwischen den beiden Formen: Ein Lambda erfasst this aus seiner Umgebung, während eine anonyme Klasse es verdeckt.

Ein ausgearbeitetes Beispiel

java— editable, runs on the server

Was kommt als Nächstes

this ist einer der zwei impliziten Verweise in Java; der andere, super, kommt ins Spiel, sobald man Vererbung hat. Vorher müssen wir jedoch über Sichtbarkeit sprechen — wer kann die Methoden und Felder Ihrer Klasse sehen und aufrufen. Weiter zu Zugriffsmodifikatoren.

Übung

Übung
Ein Konstruktor ist als public Point(int x, int y) { x = x; y = y; } geschrieben. Was ist der Fehler?
Ein Konstruktor ist als public Point(int x, int y) { x = x; y = y; } geschrieben. Was ist der Fehler?
Was this page helpful?