class AAA {
static {
System.out.println("class AAA static block println"); // 并没有打印此句
}
}
public class Main {
public static void main(String[] args) {
System.out.println("hello world!");
}
}
一直以来都以为 static 标识的代码块或者是字段,都是在类加载的时候就被执行或者赋值了,但是这么一看....感觉自己的世界观都要被刷新了。
所以此处是类没有被加载吗?还是说我们一直以来认为的,静态代码块、字段都在类加载的时候被初始化的,这个观点是错误的?
在《深入理解Java虚拟机:JVM高级特性与最佳实践 第2版》中找到一些线索,如下图:
所以,照这么说,是在第一次主动访问该类的时候执行?小弟好生迷惑啊....大家快说说你们的观点
Initialisation de classe et initialisation d'objet.
Les blocs de code et les variables contenus dans static ne sont exécutés que lorsque la classe est initialisée, et vous connaissez également les cinq conditions d'initialisation.
Veuillez expliquer clairement.
Tout d'abord, même si vous les mettez dans le même fichier .java, après compilation, ce sont toujours deux fichiers de classe différents. Si vous ne me croyez pas, jetez un œil au fichier .class généré sous le correspondant. paquet de poubelle.
Deuxièmement, lorsqu'une classe est initialisée, les variables statiques de la classe seront initialisées et le bloc de code statique sera exécuté. Par conséquent, la machine virtuelle stipule cinq conditions d'initialisation, telles que l'utilisation d'instructions new, getstatic, putstatic, la classe où se trouve la fonction principale, la réflexion, la classe parent, etc. Cependant, hormis ces cinq situations, l'initialisation de la classe ne peut pas être déclenchée. Comme indiqué dans votre code, dans Main.class, il n'y a pas d'appel, de relation parent-enfant ou de réflexion sur AAA.class. Par conséquent, AAA.class ne sera naturellement pas initialisé.
Vous pouvez lire un autre blog sur le processus de chargement des classes Java
Compris ?
-XX:+TraceClassLoading
Ajoutez ceci et vous constaterez que AAA n'est pas chargé
Il y a deux concepts qui doivent être explorés ici :
Mécanisme de chargement de classe
Java, compilateur, bytecode, spécifications et implémentation JVM.
Le chargement des classes s'effectue via le chargeur de classes (Classloader). La stratégie de chargement spécifique dépend de l'implémentation spécifique de la JVM. De manière générale, elle peut être divisée en deux types :
.Chargement affamé, chargement tant qu'il est référencé par d'autres classes.
Chargement paresseux, chargement lors de l'accès à la classe.
Java, le compilateur, le bytecode et la JVM ont leurs propres spécifications et travaillent ensemble à travers les spécifications :
Le bouton de compilation compile le code Java dans un fichier de bytecode standardisé. Chaque classe (classe externe, classe interne, classe anonyme) sera compilée dans un fichier de bytecode distinct (fichier de classe), et la JVM charge la classe à ce moment. , il est chargé un par un à partir de ces fichiers de classe.
Revenons maintenant à votre code :
Dans la couche Java, vous mettez les deux classes AAA et Main dans un seul fichier. Après compilation, le compilateur génère deux fichiers de classe : AAA.class et Main.class.
Les deux classes sont ensemble en termes d'organisation du code, mais elles sont indépendantes après compilation, et Main ne fait pas référence à AAA, donc quelle que soit la méthode de chargement de classe utilisée, elle ne déclenchera pas le chargement de la classe AAA, c'est-à-dire Les blocs de code statiques dans AAA ne seront pas exécutés.
Je remercie sincèrement les internautes enthousiastes ci-dessus pour leurs réponses !
Vérification
La classe AAA n'est effectivement pas chargée, seule la classe Main est chargée (capture d'écran de la question : la quatrième condition d'initialisation, la classe principale est automatiquement chargée par jvm)
Conclusion
Le champ statique|bloc de code dans la classe est réellement initialisé ou exécuté lorsque la classe est chargée !
Extension
Comment savoir si la classe a été chargée par jvm ?
C'est aussi un problème avec lequel j'ai été aux prises. Au début, je pensais que tant que la commande
javac
était exécutée, la classe serait chargée par la jvm. En fait, ce n'est pas le cas. La commande convertit uniquement le fichier.java
en un.class
que le jvm peut comprendre. Juste un fichier.Alors comment savoir si la classe a été chargée par jvm ?
Selon « Compréhension approfondie de la machine virtuelle Java : fonctionnalités avancées et meilleures pratiques JVM 2e édition » et les réponses enthousiastes des internautes, il n'y a pas de timing clair stipulant quand elle sera chargée !
Mais ! jvm stipule clairement le moment où une classe est initialisée - ce sont les quatre types dans la capture d'écran ci-dessus ! Le chargement de classe est prioritaire sur l'initialisation de classe, donc ici, on peut temporairement penser que ces situations sont les conditions qui déclenchent le chargement de classe.
Mon frère est ignorant et a résumé quelque chose de mal, corrigez-moi s'il vous plaît ! Merci
Mettez votre Main.java et AAA.java dans le même dossier,
Écrivez
dans la fonction principaleExécuter
Lorsque la méthode main est exécutée, seule la classe Main sera chargée. La classe AAA n'est pas utilisée dans la classe Main, et la classe AAA ne sera pas chargée. Cela ne signifie pas qu'il faut écrire les classes AAA et Main. le même fichier entraînera leur chargement simultané. Chargement
.La classe AAA n'est pas nouvelle ailleurs, elle n'obtient ni ne définit de champs statiques en conséquence, et n'invoque pas non plus de méthodes statiques.
Il ne sera donc pas initialisé automatiquement.
est placé dans deux classes. La classe principale de la classe déclarée publique commence à s'exécuter. Cette classe n'est pas utilisée et ne sera pas chargée, encore moins initialisée
.