109 votes

Comment le modificateur statique affecte-t-il ce code?

Voici mon code:

 class A {
    static A obj = new A();
    static int num1;
    static int num2=0;

    private A() {
        num1++;
        num2++;
    }
    public static A getInstance() {
        return obj;
    }
}

public class Main{
    public static void main(String[] arg) {
        A obj = A.getInstance();
        System.out.println(obj.num1);
        System.out.println(obj.num2);
    }
}
 

La sortie est 1 0 , mais je ne peux pas comprendre.

Quelqu'un peut-il me l'expliquer?

115voto

Shoaib Chikate Points 2772

En Java deux phases: 1. Identification, 2. L'exécution

  1. Dans l'identification de la phase de toutes les variables statiques sont détectés et initialisé avec les valeurs par défaut.

    Alors maintenant, les valeurs sont:
    A obj=null
    num1=0
    num2=0

  2. La deuxième phase de l'exécution, commence à partir du haut vers le bas. En Java, l'exécution commence à partir de la première de membres statiques.
    Voici votre première variable statique static A obj = new A();, alors d'abord il va créer l'objet de cette variable et d'appeler le constructeur, d'où la valeur de num1 et num2 devient 1.
    Et puis, à nouveau, static int num2=0; sera exécuté, ce qui rend num2 = 0;.

Maintenant, supposons que votre constructeur est comme ceci:

 private A(){
    num1++;
    num2++;
    System.out.println(obj.toString());
 }

Cela permettra de jeter un NullPointerException comme obj n'a toujours pas obtenu une référence de class A.

31voto

Stephen C Points 255558

Ce que l' static modificateur de moyens lorsqu'il est appliqué à une déclaration de variable est que la variable est une variable de classe plutôt qu'une variable d'instance. En d'autres mots ... il y a un seul num1 variable, et un seul num2 variable.

(Aparté: une variable statique est comme une variable globale dans quelques autres langues, sauf que son nom n'est pas visible partout. Même si elle est déclarée en tant que public static, le nom non qualifié n'est visible que si elle est déclarée dans la classe en cours ou d'une super-classe, ou si elle est importée à l'aide d'une statique à l'importation. C'est la distinction. Un vrai global est visible sans qualification n'importe où).

Ainsi, lorsque vous vous référez à l' obj.num1 et obj.num2, vous êtes en fait en se référant à la statique des variables dont les désignations sont A.num1 et A.num2. Et de même, lorsque le constructeur incréments num1 et num2, il est en incrémentant les mêmes variables (respectivement).

La confusion des rides dans votre exemple, dans la classe d'initialisation. Une classe est initialisée par le premier défaut de l'initialisation de toutes les variables statiques, puis l'exécution de l'déclaré initialiseurs statiques (et initialiseur statique blocs) dans l'ordre où ils apparaissent dans la classe. Dans ce cas, vous avez ceci:

static A obj = new A();
static int num1;
static int num2=0;

Cela se passe comme ceci:

  1. La statique commencer leur valeur par défaut valeurs initiales; A.obj est null et A.num1 / A.num2 sont de zéro.

  2. La première déclaration (A.obj) crée une instance de A(), et le constructeur A par incréments A.num1 et A.num2. Lorsque la déclaration est terminée, A.num1 et A.num2 sont à la fois 1, et A.obj se réfère à la nouvellement construit, A de l'instance.

  3. La deuxième déclaration (A.num1) n'a pas d'initialiseur, alors A.num1 ne change pas.

  4. La troisième déclaration (A.num2) a un initialiseur qui attribue à zéro A.num2.

Ainsi, à la fin de l'initialisation de classe, A.num1 est 1 et A.num2 est 0 ... ce qui est votre impression des déclarations spectacle.

Cette confusion comportement est vraiment le fait que vous êtes la création d'une instance avant l'initialisation statique est terminée, et que le constructeur vous utilisez dépend et modifie statique qui n'est pas encore initialisé. Ce quelque chose que vous devriez éviter de le faire dans le code réel.

16voto

Leonidos Points 6450

1,0 est correct.

Lorsque la classe est chargée, toutes les données statiques sont initialisées si elles sont déclarées. Par défaut, int est égal à 0.

  • le premier A est créé. num1 et num2 deviennent 1 et 1
  • que static int num1; ne fait rien
  • que static int num2=0; ceci écrit 0 pour num2

9voto

Domi Points 2724

Il est dû à l'ordre des initialiseurs statiques. Expressions statiques dans les classes sont évaluées dans un ordre de haut en bas.

Le premier à être appelé est le constructeur de A, ce qui définit num1 et num2 à la fois à 1:

static A obj = new A();

Ensuite,

static int num2=0;

est appelé et jeux de num2=0 encore.

C'est pourquoi, num1 est 1 num2 est de 0.

Comme une note de côté, un constructeur ne doit pas modifier les variables statiques, c'est très mauvais design. Au lieu de cela, essayez une approche différente de la mise en œuvre d'un Singleton en Java.

6voto

StarPinkER Points 6096

Un article dans JLS peut être trouvé: §12.4.2.

Détaillée De La Procédure D'Initialisation:

9.Ensuite, exécutez l'une des commandes de la variable de classe initialiseurs statiques et les initialiseurs de la classe, ou le domaine des initialiseurs de l'interface, dans l'ordre textuel, comme s'ils étaient un seul et unique bloc, sauf que finale de variables de classe et des champs des interfaces dont les valeurs sont des constantes de compilation sont initialisés première

Ainsi, les trois statique de la variable sera initialisée un par un dans l'ordre textuel.

Donc

static A obj = new A();
//num1 = 1, num2 = 1;
static int num1;
//this is initilized first, see below.
static int num2=0;
//num1 = 1, num2 = 0;

Si je change l'ordre de:

static int num1;
static int num2=0;
static A obj = new A();

Le résultat sera 1,1.

Notez que l' static int num1; n'est pas une variable d'initialiseur parce que(§8.3.2):

Si un champ de demande de déclaration contient une variable d'initialiseur, puis il a l' la sémantique d'une cession (§15.26) à la variable déclarée, et: Si la déclaration est une variable de classe (qui est, d'un champ statique), puis la variable d'initialiseur est évaluée et la cession effectuée exactement une fois, lorsque la classe est initialisée

Et cette variable de classe est initialisée lorsque la classe est créée. Ce qui se passe en premier(§4.12.5).

Chaque variable dans un programme doit avoir une valeur pour sa valeur est utilisé: Chaque variable de classe, variable d'instance, ou de composants de la matrice est initialisé avec une valeur par défaut lors de la création (§15.9, §15.10): Pour le type d'octets, la valeur par défaut est zéro, c'est la valeur de (byte)0. Pour le type court, la valeur par défaut est zéro, c'est la valeur de la (courte)0. Pour le type int, la valeur par défaut est zéro, c'est 0. Pour de type long, la valeur par défaut est zéro, qui est, 0L. Pour le type float, l' par défaut la valeur est positive, zéro, qui est, 0.0 f. Pour le type double, le par défaut la valeur est positive, zéro, qui est, 0.0 d. Pour le type char, le la valeur par défaut est le caractère nul, c'est-à, '\u0000'. Pour le type booléen, la valeur par défaut est false. Pour tous les types de référence (§4.3), la valeur par défaut est null.

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