(借鉴各位大神的分析并总结)
首先 静态内部类不会随着外部类的加载而加载 ,只有静态内部类的静态成员被调用时才会进行加载也就是初始化 ,这个就是调用静态内部类的静态成员,然后在初始化的过程中new一个对象。
jvm在类的初始化阶段指的是 class被加载后,被线程使用之前,在进行类初始化的时候,会有一个初始化锁,这个锁的作用是保证类初始化仅一次(因为虚拟机会保证一个类的类构造器()在多线程环境中被正确的加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的类构造器(),其他线程都需要阻塞等待,直到活动线程执行()方法完毕。特别需要注意的是,在这种情形下,其他线程虽然会被阻塞,但如果执行()方法的那条线程退出后,其他线程在唤醒之后不会再次进入/执行()方法,因为 在同一个类加载器下,一个类型只会被初始化一次。如果在一个类的()方法中有耗时很长的操作,就可能造成多个线程阻塞,在实际应用中这种阻塞往往是隐藏的
)
其次对于类初始化满足以下的条件之一就可以进行类的初始化:执行这个类静态初始化和声明的静态变量,首次发生时候,一个某个类立刻被初始化:1有一个实例创建 2静态方法调用,静态成员被赋值和使用
借鉴其他大神的总结:1.遇到new、getstatic、setstatic或者invokestatic这4个字节码指令时,对应的java代码场景为:new一个关键字或者一个实例化对象时、读取或设置一个静态字段时(final修饰、已在编译期把结果放入常量池的除外)、调用一个类的静态方法时。
2.使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没进行初始化,需要先调用其初始化方法进行初始化。
3.当初始化一个类时,如果其父类还未进行初始化,会先触发其父类的初始化。
4.当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的类),虚拟机会先初始化这个类。
5.当使用JDK 1.7等动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化。
这5种情况被称为是类的主动引用,注意,这里《虚拟机规范》中使用的限定词是"有且仅有",那么,除此之外的所有引用类都不会对类进行初始化,称为被动引用。静态内部类就属于被动引用的行列。
本人技术小白,可能写的东西就是随笔一记,如果看不懂或者有问题欢迎大家批评和提出,下次会努力改正