java - Static 标识的字段或者是代码块,真的是在类加载的时候初始化的吗?
PHPz
PHPz 2017-04-18 10:52:20
0
8
631
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版》中找到一些线索,如下图:

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

PHPz
PHPz

学习是最好的投资!

répondre à tous (8)
左手右手慢动作

类初始化和对象初始化。

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

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

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

明白了吗?

    阿神

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

      洪涛

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

      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中的静态代码块。

        左手右手慢动作

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

        验证

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

        java -XX:+TraceClassLoading Main

        结论

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

        延伸

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

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

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

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

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

          PHPzhong

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

          在main函数里写

          Class.forName("AAA");

          执行

            大家讲道理

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

              大家讲道理

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

                迷茫

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

                  Derniers téléchargements
                  Plus>
                  effets Web
                  Code source du site Web
                  Matériel du site Web
                  Modèle frontal
                  À propos de nous Clause de non-responsabilité Sitemap
                  Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!