59 votes

Pourquoi dois-je utiliser le mot-clé "this" pour les références anticipées?

Lorsque j'utilise le mot-clé this pour accéder à une variable non statique dans une classe, Java ne renvoie aucune erreur. Mais lorsque je ne l'utilise pas, Java renvoie une erreur. Pourquoi dois-je utiliser this ?

Je sais normalement quand je devrais utiliser this, mais cet exemple est très différent des utilisations normales.

Exemple :

class Foo {
//  int a = b; // donne une erreur. pourquoi ?
    int a = this.b; // pas d'erreur. pourquoi ?
    int b;
    int c = b;

    int var1 = this.var2; // très intéressant
    int var2 = this.var1; // très intéressant
}

71voto

Erwin Bolwidt Points 5566

La description complète se trouve dans la section 8.3.3 de la spécification du langage Java : "Références Avant l'Initialisation des Champs"

Une référence avant (référence à une variable qui n'est pas encore déclarée à ce moment-là) n'est considérée comme une erreur que si toutes les conditions suivantes sont remplies :

  • La déclaration d'une variable d'instance dans une classe ou interface C apparaît textuellement après une utilisation de la variable d'instance ;

  • L'utilisation est un simple name soit dans un initialisateur de variable d'instance de C soit dans un initialiseur d'instance de C ;

  • L'utilisation ne se trouve pas du côté gauche d'une affectation ;

  • C est la classe ou interface la plus imbriquée contenant l'utilisation.

Voir le texte en gras : "l'utilisation est un simple name". Un simple name est un nom de variable sans qualification supplémentaire. Dans votre code, b est un simple name, mais this.b ne l'est pas.

Mais pourquoi ?

La raison est, comme le texte en italique dans l'exemple de la JLS l'indique :

"Les restrictions ci-dessus sont conçues pour détecter, au moment de la compilation, des initialisations circulaires ou autrement mal formées. "

En d'autres termes, elles autorisent this.b car elles pensent qu'une référence qualifiée rend plus probable que vous avez bien réfléchi à ce que vous faites, mais simplement utiliser b signifie probablement que vous avez fait une erreur.

C'est la logique des concepteurs du langage Java. À ma connaissance, il n'a jamais été étudié si cela était vrai en pratique.

Ordre d'initialisation

Pour approfondir ce qui précède, en référence au commentaire de Dukeling sur la question, l'utilisation d'une référence qualifiée this.b ne vous donnera probablement pas les résultats que vous souhaitez.

Je restreins cette discussion aux variables d'instance car l'OP s'y est seulement référé. L'ordre dans lequel les variables d'instance sont assignées est décrit dans JLS 12.5 Création de Nouvelles Instances de Classe. Vous devez prendre en compte que les constructeurs de superclasses sont invoqués en premier, et que le code d'initialisation (affectations et blocs d'initialisation) est exécuté dans l'ordre textuel.

Ainsi, étant donné

int a = this.b;
int b = 2;

vous obtiendrez a étant égal à zéro (la valeur de b au moment où l'initialiseur de a a été exécuté) et b étant égal à 2.

Des résultats encore plus étranges peuvent être obtenus si le constructeur de la superclasse invoque une méthode qui est redéfinie dans la sous-classe et que cette méthode affecte une valeur à b.

Donc, en général, il est une bonne idée de faire confiance au compilateur et de soit réorganiser vos champs soit de corriger le problème sous-jacent en cas d'initialisations circulaires.

Si vous avez besoin d'utiliser this.b pour contourner l'erreur du compilateur, alors vous êtes probablement en train d'écrire un code qui sera très difficile à maintenir pour la personne qui viendra après vous.

45voto

Jason Points 2877

Les variables sont déclarées d'abord, puis assignées. Cette classe est la même que celle-ci :

class Foo {
    int a;
    int b;
    int c = b;

    int var1;
    int var2;

    public Foo() {
        a = b;

        var1 = var2;
        var2 = var1;
    }
}

La raison pour laquelle vous ne pouvez pas faire int a = b; est parce que b n'est pas encore défini au moment où l'objet est créé, mais l'objet lui-même (c'est-à-dire this) existe avec toutes ses variables membres.

Voici une description pour chacune :

    int a = b; // Erreur : b n'a pas encore été défini
    int a = this.b; // Pas d'erreur : 'this' a été défini ('this' est toujours défini dans une classe)
    int b; 
    int c = b; // Pas d'erreur : b a été défini à la ligne précédente

4voto

Wajid Ali Points 455

Vous avez présenté 3 cas :

  1. int a = b; int b;
    Cela donne une erreur car le compilateur cherchera b dans la mémoire et il ne sera pas là. mais lorsque vous utilisez le mot-clé this, cela spécifie explicitement que le b est défini dans le cadre de la classe, toutes les références de classe le chercheront, et finalement le trouveront.

  2. Le deuxième scénario est assez simple et comme je l'ai décrit, b est défini dans le cadre avant c et ne posera pas de problème en cherchant b dans la mémoire.

  3. int var1 = this.var2;
    int var2 = this.var1;
    Dans ce cas, il n'y a pas d'erreur car dans chaque cas la variable est définie dans la classe et l'assignation utilise this qui cherchera la variable assignée dans la classe, et non seulement dans le contexte qui le suit.

4voto

Arun Sudhakaran Points 1229

Pour n'importe quelle classe en Java this est une variable de référence par défaut (lorsqu'aucune référence spécifique n'est donnée) que l'utilisateur peut donner ou que le compilateur fournira à l'intérieur d'un bloc non statique. Par exemple

public class ThisKeywordForwardReference {

    public ThisKeywordForwardReference() {
        super();
        System.out.println(b);
    }

    int a;
    int b;

    public ThisKeywordForwardReference(int a, int b) {
        super();
        this.a = a;
        this.b = b;
    }

}

Vous avez dit que int a = b; // gives error. why ? donne une erreur de compilation car b est déclaré après a ce qui est une Référence Avancée Illégale en Java et considérée comme une erreur de compilation.

Mais dans le cas des méthodes la Référence Avancée devient légale

int a = test();
int b;

int test() {
    return 0;
}

Mais dans mon code, le constructeur avec l'argument est déclaré avant à la fois a & b, mais ne donne aucune erreur de compilation car System.out.println(b); sera remplacé par System.out.println(this.b); par le compilateur.

Le mot clé this signifie simplement la référence de la classe actuelle ou la référence sur laquelle la méthode, le constructeur ou l'attribut est accédé.

A a1 = new A();  // Ici this n'est rien d'autre que a1
a1.test();  // Ici this est à nouveau a1

Quand nous disons a = this.b; cela spécifie que b est un attribut de la classe actuelle, mais quand nous disons a = b; puisque ce n'est pas à l'intérieur d'un bloc non statique this ne sera pas présent et cherchera un attribut déclaré précédemment qui n'est pas présent.

3voto

leshkin Points 2072

Veuillez consulter la spécification du langage Java : https://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.2.3

C'est la raison, à mon avis : L'utilisation se fait via un simple nom.

Donc dans ce cas, vous devez spécifier le nom en utilisant this.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X