3
votes

pourquoi le bloc statique ne peut pas accéder à la variable statique définie après

J'ai vérifié Transférer les références lors de l'initialisation du champ et cette la réponse de @assylias , mais je n'ai toujours pas de réponse à la pourquoi .

Pourquoi un bloc statique peut affecter la variable statique déclarée après lui mais ne peut PAS y accéder?

   class Parent {
        static {
            i = 2; // valid
            // can only assign new value to it instead of accessing it?
//            System.out.println(i); // invalid - compile-error
        }
        static int i = 0;
        static {
            i = 3; // valid
        }
    }

Est-ce dû au fait: la valeur n'est pas encore initialisée, donc nous vous interdisons explicitement de l'utiliser? ou il y a quelque chose lié à la sécurité que je ne sais pas?


mis à jour

ce n'est pas un doublon de ce problème qui concerne

Pourquoi cela ne se produit pas lors de l'accès avec nom de classe ?

Cette question est de savoir pourquoi nous avons ce design? dans quel but?


8 commentaires

il y aura une erreur de compilation comme mentionné @Lino donc vous ne pouvez tout simplement pas obtenir le bytecode


@Lino Ce code ne se compile pas. Il n'y a pas de bytecode à vérifier. Ne postez pas de suppositions inutiles ici.


Oui, c'est parce qu'il n'est pas encore initialisé, c'est ce que dit le message d'erreur, n'est-ce pas?


Copie possible de Pourquoi un transfert illégal erreur de référence non affichée lors de l'utilisation d'une variable statique avec un nom de classe


@Lino veuillez vérifier la mise à jour pour un problème de duplication


@Hearen Demander pourquoi les désications linguistiques ne sont pas des questions faciles à répondre. Cela nécessite des connaissances assez approfondies de l'un des développeurs Java et à moins que Brian Goetz ne vienne, je ne suis pas sûr que quelqu'un ici puisse répondre à cette question.


Merci pour l'aide. Désolé de publier une telle question. Mais d'abord, ce n'est pas un doublon; deuxièmement, je sais que cette question n'est pas simple (même si vous avez dit une question impossible) et c'est pourquoi ajouter ce message dans la question lorsque je la lance: "Il y aura des votes négatifs, mais je viens de perdre l'indice dans la forêt." qui est supprimé par luk2302.


@Lino Merci pour l'aide en cours de route. Mon idée est simple: je veux l'apprendre et la comprendre. Désolé de vous déranger beaucoup :) bonne journée;)


3 Réponses :


4
votes

Les champs statiques sont initialisés en fonction de l'ordre dans lequel ils apparaissent dans le code.

Ainsi, lorsque vous attribuez une valeur à la variable i , il vous suffit de dire au compilateur : "Hé, mec, quand tu arrives à initialiser cette variable, règle sa valeur sur ...". Mais vous ne pouvez pas l'utiliser tant qu'il n'a pas été initialisé car il n'existe tout simplement pas encore.

MISE À JOUR:

Comme il est dit dans le livre "The Java Language Specification" de James Gosling, Bill Joy, Guy Steele et Gilad Bracha:

Ces restrictions sont conçues pour intercepter, au moment de la compilation, circulaires ou sinon initialisations mal formées.

Considérez ceci:

static {
            i = 2;
            j = i + 5; //should it be 7 or 15?
}
static int i = 10;
static int j;

La variable j devrait-elle être 7 ou 15? Si c'est 7, alors nous avons initialisé la variable i deux fois, ce qui n'est pas possible, car le champ est statique. Si c'est 15 alors que signifie i = 2; ?

Ce code est ambigu, donc la spécification Java ne permet pas de le faire.


4 commentaires

Fourni quelques explications.


Woah, merci beaucoup. Je viens de me perdre et je ne sais pas pourquoi cela n'est pas autorisé. Cet exemple me donne un indice. Merci beaucoup! Pavel


" alors nous avons initialisé la variable i deux fois, ce qui n'est pas possible, puisque le champ est statique " ahem, pourquoi pensez-vous que ce n'est pas possible? Vous pouvez attribuer une variable aussi souvent que vous le souhaitez, sauf si elle est final . Vous pouvez facilement écrire static int i = 2, j = i ++ + 5; statique {i + = 3; } Ou vous changez j = i + 5; dans votre propre exemple en j = ClassName.i + 5; et cela fonctionne, comme la variable existe déjà.


Il le dit dans la spécification Java: "Au moment de l'exécution, l'initialiseur est évalué et l'affectation est exécutée exactement une fois, lorsque la classe est initialisée". Ici docs.oracle.com /javase/specs/jls/se8/html/jls-8.html#jls-8.3‌ .3 et ici docs.oracle.com/javase/specs/jls/se8/html/... À propos du référencement d'une variable par son nom complet. Dans ce cas, le compilateur sait exactement que la classe a déjà été initialisée Cette question a été abordée ici: stackoverflow.com/questions/29153703/...



0
votes

Après quelques lectures supplémentaires, je pense que Pavel n'est pas tout à fait exact sur ce point car @ Holger a souligné dans le commentaire.

nous avons initialisé la variable i deux fois, ce qui n'est pas possible, car le champ est statique.

Comme le 12.4.2. La procédure d'initialisation détaillée souligne

Pour chaque classe ou interface C, il existe un verrou d'initialisation unique LC . Le mappage de C à LC est laissé à la discrétion de l'implémentation de la machine virtuelle Java.

Je suppose que l'initialisation deux fois convient à l'initialiseur de classe lui-même tant que ce n'est que une fois pour les clients qui invoquent.

Mais les démos fournies par Pavel tiennent toujours sa place, donc je les réutilise simplement ici mais avec des explications différentes.

static {
       i = 2;
       j = i + 5; 
       // no one knows whether "i" here initialized properly here
}
static int i = 10;
static int j;

Mais lorsque vous utilisez MyClass.i directement dans j = MyClass.i + 5 , le compilateur le saurait ce serait alors bien comme 8.3.3. Renvoyer les références lors de l'initialisation du champ détaillé avec quatre conditions.

Plus précisément, il s'agit d'une erreur de compilation si tous les éléments suivants sont vrai:

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

  2. L'utilisation est un nom simple soit dans un initialiseur de variable de classe de C ou un initialiseur statique de C;

  3. L'utilisation n'est pas sur le côté gauche d'un devoir;

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

Et il y a déjà une discussion détaillée dans cette réponse .

Pour terminer, je pense que ce serait pour comportement prévisible d'ajouter ces restrictions. Une fois de plus, l'autre objectif officiel indiqué dans 8.3.3. Transférer les références lors de l'initialisation du champ .

Ces restrictions sont conçues pour intercepter, au moment de la compilation, les initialisations circulaires ou autrement mal formées.


0 commentaires

0
votes

La même chose s'applique également aux membres non statiques. Vous pouvez leur attribuer des valeurs dans le bloc d'initialisation d'instance, mais vous ne pouvez pas les utiliser avant l'initialisation.

class Parent {
    {
        x = 3; // works fine
        // System.out.println(x); // gives compilation error.

    }
    int x = 0;

    public static void main(String[] args) {

    }
}


0 commentaires