web-dev-qa-db-fra.com

Pourquoi .class n'appelle-t-il pas le bloc statique dans une classe?

Voici le code que j'ai:

public class StupidClass {
    static {
        System.out.println("Stupid class loaded!");
    }
}

Et les tests que j'ai, que je lance séparément .

import org.junit.Test;

public class StupidTest {
    @Test
    public void foo() throws ClassNotFoundException {
        final Class<?> stupidClass = Class.forName("StupidClass");
        System.out.println(stupidClass.getSimpleName());
    }

    @Test
    public void bar() throws ClassNotFoundException {
        final Class<StupidClass> stupidClassClass = StupidClass.class;
        System.out.println(stupidClassClass.getSimpleName());
    }
}

Quand je lance test foo je vois:

Stupid class loaded!
StupidClass

Mais quand je lance la barre de test tout ce que je vois c'est:

StupidClass

Citant de this page ..

Les objets de classe sont construits automatiquement par la machine virtuelle Java lorsque les classes sont chargées et par des appels à la méthode defineClass dans le chargeur de classe.

Donc, si je comprends bien, dans la barre de test, la classe Stupid est chargée, sinon j'aurais vu un nul je suppose? L'objet Class est donc créé car la classe elle-même est chargée.

Et maintenant, citant this page

Les blocs d'initialisation statiques sont exécutés lorsque la JVM (chargeur de classe - pour être spécifique) charge StaticClass (qui se produit la première fois qu'il est référencé dans le code).

Je m'attends donc à voir la "classe stupide chargée!" texte dans la barre de test aussi, mais je ne le suis pas.

Citant également de Penser en Java

Chacune des classes Candy, Gum et Cookie a une clause statique qui est exécutée lors du premier chargement de la classe.

ce qui n'est pas très précis semble-t-il ..

Qu'est-ce que je rate?

68
Koray Tugay

Les blocs d'initialisation statiques sont exécutés lorsque la JVM (chargeur de classe - pour être spécifique) charge StaticClass (qui se produit la première fois qu'il est référencé dans le code).

La citation ci-dessus est tout à fait fausse, mais ce n'est qu'un exemple d'une idée fausse très répandue.

  1. La classe n'est pas initialisée lors du chargement, mais lorsqu'un membre de classe statique est d'abord référencé. Ceci est précisément régi par la spécification .

  2. Le chargement de classe ne se produit pas lorsque la classe est référencée pour la première fois, mais à un point dépendant de l'implémentation.

  3. Le dernier moment où la classe doit être chargée est lorsque la classe est référencée, ce qui n'est pas différent que de référencer une classe membre .

Class.forName initialise la classe par défaut, mais vous avez le choix d'appeler une surcharge qui prend un boolean initialize et fournir false. Vous obtiendrez la classe chargée sans initialisation.

59
Marko Topolnik

Le chargement et l'initialisation de classe sont deux choses différentes. Une classe peut être chargée mais pas initialisée jusqu'à ce qu'elle soit vraiment nécessaire. Les initialiseurs statiques ne sont exécutés que lorsqu'une classe est initialisée <> NON chargée, "initialisée"

Dans le premier cas, vous chargez et initialisez une classe lorsque vous utilisez class.forName(), c'est pourquoi les initialiseurs statiques sont exécutés et donc vous voyez "Stupid class loaded!" En sortie. Dans le second cas, vous assignez simplement une référence à la classe, la classe est chargée (utilisez Java -verbose: class pour voir quelles classes sont chargées) mais vous ne l'initialisez pas vraiment (ou pour être plus précis, ne faites rien qui oblige les initialiseurs à s'exécuter). Ainsi, vous ne voyez pas la sortie comme Stupid class loaded!. Essayez de faire quelque chose comme appeler newInstance() sur la classe, cela devrait forcer l'initialisation de la classe et vous devriez voir Stupid class loaded!

Mon code:

public class CheckPalindrome {

    public static void main(String[] args) {
        Class<Test> t = Test.class;
    }

}
// class being loaded
class Test {
    static {
        System.out.println("aaa");
    }
}

Classes chargées

...
[Loaded Test from file:/Workspaces/SampleTest/Java8/bin/]
...

^ - Cela montre que la classe est chargée mais pas initialisée.

22
TheLostMind