web-dev-qa-db-fra.com

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

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

Je sais quand utiliser normalement this, mais cet exemple est très différent des usages normaux.

Exemple:

class Foo {
//  int a = b; // gives error. why ?
    int a = this.b; // no error. why ?
    int b;
    int c = b;

    int var1 = this.var2; // very interesting
    int var2 = this.var1; // very interesting
}
59
Nomad

Les variables sont déclarées en premier, puis attribué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 de la création de l’objet, mais que l’objet lui-même (c.-à-d. this) existe avec toutes ses variables membres.

Voici une description pour chacun:

    int a = b; // Error: b has not been defined yet
    int a = this.b; // No error: 'this' has been defined ('this' is always defined in a class)
    int b; 
    int c = b;  // No error: b has been defined on the line before  
45
Jason

La description complète est en section 8.3.3 de la Java Spécification de la langue: " Références en avant lors de l'initialisation du champ "

Une référence en aval (faisant référence à une variable qui n'est pas encore déclarée à ce stade) n'est une erreur que si les conditions suivantes sont toutes vraies:

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

  • L'utilisation est un nom simple dans un initialiseur de variable d'instance de C ou un initialiseur d'instance de C;

  • L’utilisation n’est pas à gauche d’une mission;

  • C est la classe ou l'interface la plus interne englobant l'utilisation.

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

Mais pourquoi?

La raison en est, comme le dit le texte cursif dans l'exemple du JLS:

"Les restrictions ci-dessus sont conçues pour intercepter, au moment de la compilation, des initialisations circulaires ou malformées."

En d’autres termes, ils autorisent this.b Car ils pensent qu’une référence qualifiée augmente la probabilité que vous pensiez bien à ce que vous faites, mais le fait d’utiliser simplement b signifie probablement que vous avez erreur.

C’est la raison d’être des concepteurs du Java) Langage. Que cela soit vrai en pratique n’a jamais été étudié à ma connaissance.

Ordre d'initialisation

Pour développer 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 souhaités.

Je limite cette discussion aux variables d'instance car le PO ne les a que référencées. L'ordre dans lequel les variables d'instance sont affectées est décrit dans JLS 12.5 Création d'instances de classe nouvelles . Vous devez tenir compte du fait que les constructeurs de la super-classe sont d'abord appelés et que le code d'initialisation (affectations et blocs d'initialisation) est exécuté dans l'ordre textuel.

Donc donné

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

vous vous retrouverez avec a égal à zéro (la valeur de b au moment de l'exécution de l'initialiseur de a) et à b égale à 2.

Même des résultats plus bizarres peuvent être obtenus si le constructeur de la superclasse appelle une méthode qui est remplacée dans la sous-classe et que cette méthode attribue une valeur à b.

Donc, en général, il est judicieux de croire le compilateur et de réorganiser vos champs ou de résoudre le problème sous-jacent en cas d’initialisations circulaires.

Si vous devez utiliser this.b Pour contourner l'erreur du compilateur, vous écrivez probablement un code qui sera très difficile à gérer par la personne qui vous suit.

71
Erwin Bolwidt

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 this mot-clé, il spécifie explicitement que le b est défini dans l'étendue de la classe. Toutes les références de classe seront donc recherchées et finalement, il le trouvera.
  2. Le second scénario est assez simple et comme je l’ai décrit, b est défini dans l’étendue avant c et ne posera pas de problème si vous recherchez b dans la mémoire.
  3. int var1 = this.var2;
    int var2 = this.var1;
    Dans ce cas, pas d'erreur, car dans chaque cas, la variable est définie dans la classe et l'affectation utilise this qui recherchera la variable affectée dans la classe, et pas seulement le contexte dans lequel elle est suivie.
4
Wajid Ali

Pour toute classe dans 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 ? Donnait une erreur de compilation car b est déclaré après a qui est un Illegal Forward Reference In Java et considéré comme une erreur de compilation.

Mais dans le cas de methodsForward Reference Devient légal

int a = test();
int b;

int test() {
    return 0;
}

Mais dans mon code, le constructeur avec l'argument est déclaré avant les deux a & b, sans donner d'erreur de compilation, car System.out.println(b); sera remplacé par System.out.println(this.b); par le compilateur.

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

A a1 = new A();  // Here this is nothing but a1
a1.test();  // Here this is again a1

Lorsque nous disons a = this.b;, Nous spécifions que b est un attribut de classe actuel, mais lorsque nous disons a = b; Car il ne se trouve pas dans un bloc non statique this ne sera pas présent et recherchera un attribut déclaré précédemment qui n'est pas présent.

4
Arun Sudhakaran

Veuillez consulter le Java: https://docs.Oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3 .2.

C'est la raison, IMO: The usage is via a simple name.

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

3
leshkin