suchen

Heim  >  Fragen und Antworten  >  Hauptteil

java - Static 标识的字段或者是代码块,真的是在类加载的时候初始化的吗?

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版》中找到一些线索,如下图:

所以,照这么说,是在第一次主动访问该类的时候执行?小弟好生迷惑啊....大家快说说你们的观点

PHPzPHPz2812 Tage vor723

Antworte allen(8)Ich werde antworten

  • ringa_lee

    ringa_lee2017-04-18 10:54:20

    类初始化和对象初始化。

    static包含的代码块和变量只有在类初始化的时候才执行,而初始化的五种条件你也知道啦。

    补充说明清楚吧。
    首先,你即使放在同一个.java文件中,编译后,这还是两个不同的class文件,不信你看看bin对应的包下面生成的.class文件。
    第二,类初始化的时候,就会初始化类的静态变量和运行静态代码块。所以,虚拟机规定了五种初始化的条件,比如使用了new,getstatic,putstatic指令,main函数所在的类,反射,父类等情况。而,除开这五种情况,是不能触发类的初始化的。正如你代码中所示Main.class中,并没有任何关于AAA.class的调用或者父子关系或者反射。所以,AAA.class自然不会初始化。

    可以看看的另一篇博客java类的加载过程

    明白了吗?

    Antwort
    0
  • 阿神

    阿神2017-04-18 10:54:20

    -XX:+TraceClassLoading
    加上这个会发现没加载AAA

    Antwort
    0
  • PHP中文网

    PHP中文网2017-04-18 10:54:20

    这里有两个概念需要撸一下:

    1. 类加载机制

    2. Java、编译器、字节码、JVM的规范和实现。

    类的加载是通过类加载器(Classloader)完成的,加载的具体策略依赖JVM的具体实现,总的来说可以分两种:

    1. 饥饿式加载,只要被其他类引用到了就加载。

    2. 懒惰式加载,当类被访问的时候才加载。

    Java、编译器、字节码、JVM有各自的规范,彼此通过规范协同工作:

    编译按把Java代码编译成规范的字节码文件,每一个类(外部类、内部类、匿名类)都会被编译成一个单独的字节码文件(class文件),JVM加载类的时候就是从这些class文件中一个个的加载。

    现在回到你的代码:

    在Java层,你把AAA、Main两个类放在一个文件中,编译器编译后生成两个class文件:AAA.class、Main.class。
    两个类在代码组织形式上是一起的,但是编译后却是独立的,并且Main并没有引用AAA,所以无论是哪种类加载方式都不会触发对类AAA的加载,也就不会执行AAA中的静态代码块。

    Antwort
    0
  • ringa_lee

    ringa_lee2017-04-18 10:54:20

    真心感谢楼上热心网友们的解答!

    验证

    AAA 类确实没有被加载,只有 Main 类被加载(题干截图:初始化条件第四条,主类被 jvm 自动加载)

    java -XX:+TraceClassLoading Main

    结论

    类中 静态字段|代码块 真的是在类加载的时候被初始化或者是执行的!

    延伸

    怎么知道类有没有被 jvm 所加载?

    这也是我一直纠结的问题,一开始以为只要执行了 javac 命令,类就被 jvm 加载了,其实不然,该命令只是将 .java 文件转化成 jvm 能读懂的 .class 文件而已。

    那么到底怎么知道类有没有被 jvm 所加载?
    据 《深入理解Java虚拟机:JVM高级特性与最佳实践 第2版》 和广大网友的热心解答可知,并没有明确的时机规定了啥时候会被加载!

    但是!jvm 明确规定了类被初始化的时机-就是题干上截图部分那四种!而类的加载是优先于类初始化的,所以这里,我们暂且可以认为这几种情况就是触发类加载的条件。

    小弟愚昧,总结不妥之处,还麻烦大家指正!感谢

    Antwort
    0
  • PHPz

    PHPz2017-04-18 10:54:20

    把你的Main.java和AAA.java放在同一个文件夹里,

    在main函数里写

    Class.forName("AAA");
    

    执行

    Antwort
    0
  • 大家讲道理

    大家讲道理2017-04-18 10:54:20

    执行main方法时,只会加载Main类,Main类中并没有使用到AAA类,并不会去加载AAA类,并不是说把AAA和Main两个类写到同一个文件就会同时加载

    Antwort
    0
  • 大家讲道理

    大家讲道理2017-04-18 10:54:20

    AAA这个类既没有在其他地方new,也没有对应的去获取或者设置静态的字段,也没有去invoke静态方法。
    所以不会自动初始化的。

    Antwort
    0
  • 迷茫

    迷茫2017-04-18 10:54:20

    放在两个类里面了,声明为public的类中的mian开始执行,那个类没被用到自然不会被加载更别提初始化

    Antwort
    0
  • StornierenAntwort