W3docs

Le mot-clé this en Java

Référencez l'objet courant en Java avec le mot-clé this — désambiguïsation des champs, chaînage de constructeurs et appels de méthodes.

Dans une méthode d'instance ou un constructeur, this désigne l'objet sur lequel la méthode est appelée. C'est un paramètre implicite que la JVM vous passe automatiquement. La plupart du temps, vous n'avez pas besoin de le mentionner — les noms simples sont déjà résolus via this — mais quelques situations vous obligent à l'écrire explicitement. Ce chapitre les passe en revue.

Ce qu'est this

Lorsque vous appelez dog.bark(), la JVM passe secrètement dog comme premier argument. À l'intérieur de bark, cet argument s'appelle this. Ainsi :

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

Vous pouvez omettre this. et écrire simplement name — Java cherche l'identifiant nu dans la portée courante, ne trouve pas de variable locale avec ce nom, remonte jusqu'aux champs de l'instance, trouve name, et le résout comme this.name. Les deux formes produisent le même bytecode.

Utilisation 1 — désambiguïser un paramètre d'un champ

La raison la plus courante d'écrire this. explicitement est quand un paramètre ou une variable locale porte le même nom qu'un champ :

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

Sans this., x = x; assignerait le paramètre à lui-même et laisserait le champ à 0. Le compilateur n'avertit pas — c'est une instruction valide — ce qui en fait un bug silencieux très courant.

Vous pourriez renommer les paramètres (int newX, int newY) pour éviter la collision, mais faire correspondre les noms des paramètres à ceux des champs est de loin la convention la plus lisible, et le schéma this. est donc omniprésent dans le code Java.

Utilisation 2 — passer l'objet courant

Parfois, une méthode doit transmettre this à une autre méthode ou à un constructeur en tant qu'argument :

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

Il n'existe aucun autre moyen de faire référence à l'objet courant en tant que valeur, donc this est obligatoire ici.

Une variante courante est un builder fluide où chaque setter retourne this afin que les appels puissent être chaînés :

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");

Utilisation 3 — this(...) pour appeler un autre constructeur

À l'intérieur d'un constructeur, this(args) appelle un autre constructeur de la même classe — voir les constructeurs. Cela doit être la première instruction, et un constructeur ne peut déléguer qu'à un seul autre :

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

Cette forme est différente du qualificateur this.this(...) avec des arguments est la forme d'appel de constructeur ; this.foo (ou this seul) est la forme de référence.

Quand this est illégal

this n'existe que dans les contextes d'instance. Depuis une méthode ou un initialiseur static, il n'y a pas d'objet courant, et écrire this provoque une erreur de compilation :

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

main est static, c'est pourquoi vous ne pouvez pas faire référence directement aux champs d'instance à l'intérieur — vous devez d'abord créer un objet.

this vs accès implicite aux champs

En l'absence de collision de noms, this. est purement stylistique :

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

Les deux fonctionnent. La forme implicite est plus courante ; certaines bases de code utilisent this. partout par souci de cohérence ou pour rendre le récepteur visible au premier coup d'œil. L'une ou l'autre convient — choisissez-en une et appliquez-la de manière uniforme dans un fichier.

Classes internes et le this externe

Une classe interne non statique possède une référence implicite à son instance englobante. Depuis la classe interne, this désigne l'objet interne ; l'instance externe est 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
    }
  }
}

Cela n'apparaît que dans les scénarios de classes imbriquées, traités dans les classes imbriquées et les chapitres suivants.

Lambdas vs classes anonymes

Un lambda n'introduit pas de nouveau this. À l'intérieur d'un lambda, this est l'instance englobante — le même objet sur lequel s'exécute la méthode environnante. Une classe anonyme, en revanche, est son propre objet, donc à l'intérieur, this désigne cette instance anonyme :

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
  }
}

C'est l'une des rares différences de comportement entre les deux formes : un lambda capture this de son environnement, tandis qu'une classe anonyme le masque.

Un exemple concret

java— editable, runs on the server

Et ensuite

this est l'une des deux références implicites en Java ; l'autre, super, intervient dès que vous avez de l'héritage. Avant cela, nous devons parler de la visibilité — qui peut voir et appeler les méthodes et les champs de votre classe. Continuez vers les modificateurs d'accès.

Pratique

Pratique
Un constructeur est écrit comme public Point(int x, int y) { x = x; y = y; }. Quel est le bug ?
Un constructeur est écrit comme public Point(int x, int y) { x = x; y = y; }. Quel est le bug ?
Was this page helpful?