35 votes

L’initialisation récursive fonctionne lorsque j’ajoute "ceci"?

La compilation échoue (avec une erreur illegal forward reference ), comme on pouvait s'y attendre:

 class test {
    int x = x + 42;
}
 

Mais cela fonctionne:

 class test {
    int x = this.x + 42;
}
 

Que se passe-t-il? Qu'est-ce qui est assigné dans ce dernier cas?

18voto

bayou.io Points 3680

Il est trop difficile à découvrir et à interdire tout accès à l' x pendant x initialisation. Par exemple

int x = that().x;                |    int x = getX();
                                 |
Test that(){ return this; }      |    int getX(){ return x; }

La spécification s'arrête à "l'accès par le simple nom de" et de ne pas essayer d'être plus complet.

Dans un autre article, "Certaine" d'Assignation, la spécification ne fait la même chose. Par exemple

public class Test
{
    static final int y;
    static final int z = y;  // fail, y is not definitely assigned 
    static{ y = 1; }
}

public class Test
{
    static final int y;
    static final int z = Test.y;  // pass... because it's not a simple name
    static{ y = 1; }
}

Il est intéressant de noter, "Certaine Affectation" mentionne spécifiquement que this.x est équivalent à x

(ou, pour un champ, le simple nom de domaine qualifié par cet)

cette clause pourrait être ajouté à la section cité par NPE ainsi.

  • l'utilisation se fait via un simple nom (ou un nom simple qualifiés par cet)

Mais en fin de compte, il est impossible au moment de la compilation d'analyser toutes les utilisations possibles/accède à un champ.

17voto

NPE Points 169956

Résumé: à la Fois les initialiseurs d'accéder à un champ c'est pas encore initialisé (et donc encore a la valeur par défaut de zéro). Puisque c'est probablement une erreur de programmation, le langage des interdictions de certaines des formes simples d'accès. Cependant, il n'a pas d'interdiction de forme plus complexe.

Le comportement est conforme à la JLS, spécialement §8.3.2.3. Restrictions sur l'utilisation de Champs lors de l'Initialisation

La déclaration d'un membre doit apparaître sous forme de texte avant de l'utiliser seulement si le membre est une instance (respectivement static) champ d'une classe ou d'une interface C et de toutes les conditions suivantes s'appliquent:

  • L'utilisation se produit dans une instance (respectivement static) de la variable d'initialiseur de C ou dans une instance (respectivement static) de l'initialiseur de C.

  • L'utilisation n'est pas sur le côté de main gauche d'une affectation.

  • L'utilisation se fait via un simple nom.

  • C le plus proche du centre de la classe ou de l'interface en joignant l'utilisation.

Le premier exemple qui répond à tous les quatre conditions et est donc invalide. Le deuxième exemple n'est pas satisfaire à la troisième condition (this.x n'est pas un simple nom), et est donc OK.

L'ensemble de la séquence des événements est la suivante:

Ainsi, si un initialiseur fait référence à un domaine qui apparaît plus loin dans la définition de la classe (ou du champ lui-même), il serait de voir la valeur par défaut de cet autre champ. C'est probablement une erreur de programmation et est donc explicitement interdites par le §8.3.2.3.

Si vous contourner §8.3.2.3, par exemple, à l'aide de this. vers l'avant et le faire référence à un champ, vous verrez la valeur par défaut (zéro pour int). Ainsi, la suite est bien définie et est garanti pour définir x de 42:

class test {
    int x = this.x + 42;
}

1voto

Dans le premier cas, le compilateur essaie d'évaluer l'expression 'x + 42' mais échoue car x n'est pas initialisé.

Dans le second cas, l'expression 'this.x + 42' est évaluée au moment de l'exécution (à cause du mot clé 'this'), lorsque x est déjà initialisé et a la valeur 0.

0voto

IndoKnight Points 1269

Vous obtiendrez 42 dans ce dernier cas. Lorsque vous utilisez ce (mot-clé), il est entendu que l'objet est déjà créé. Mais, quelle est la valeur de x quand un objet est créé? c'est 0! C'est pareil que ce code

 class test{
    int x;        
     {
    x  = this.x + 42;
     }
}
 

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