目录
被动引用:关于不会初始化的场景
接口类的加载
最后
类的加载主要有三步:加载->连接->初始化。连接过程又分为 验证->准备->解析。
类是通过.java---complier----.class---classloader--Class,然而这个加载又分为以上的7大步骤,那什么时候类开始加载?什么条件必须会加载?什么时候不会被加载?
主动引用:jdk1.7的时候只有5种加载方式,但是jdk1.8及以及类有6种必须对类初始化的条件:
遇到new、getstatic、putstatic或invokestatic必须进行初始化;
//new必须初始化
SuperClass superClass = new SuperClass();
使用java.lang.reflect包的方法对类型进行反射调用的时候,被调用的必须进行初始化;
//反射必须被初始化
SuperClass superClass =SuperClass.class.newInstance();
当初始化类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化;
//子类继承父类,并且引用父类变量父类会被初始化
public class SuperClass {
static {
System.out.println("父类SuperClass init!");
}
public static int value = 123;
}
public class SubClass extends SuperClass {
static {
System.out.println("子类SubClass init!");
}
}
当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先初始化这个主类;
//main方法会被初始化
public static void main(String[] args) {
System.out.println("肯定会被初始化!");
}
当使用JDK 7新加入的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果为REF_getStatic、REF_putStatic、REF_invokeStatic、REF_newInvokeSpecial先进行初始化!
当一个接口中定义了JDK 8新加入的默认方法,有接口实现初始化,则父类必须初始化!
以上这6种方法是虚拟机规定的必须会被加载,也叫主动引用,除此之外所有引用类的方式都不会触发初始化,也叫被动引用。
被动引用:关于不会初始化的场景
1.通过子类引用父类的静态字段,不会导致子类初始化
/**
*
* 功能描述: 子类实现父类
*
* @param:
* @return:
* @auther: csh
* @date: 2021/3/3 16:18
*/
public class SubClass extends SuperClass {
static {
System.out.println("子类SubClass init!");
}
}
/**
*
* 通过子类引用父类的静态字段,不会导致子类初始化
**/
public class SuperClass {
static {
System.out.println("父类SuperClass init!");
}
public static int value = 123;
}
/**
* 非主动使用类字段演示
**/
public class NotInitialization {
public static void main(String[] args) {
System.out.println(SubClass.value);
}
}
结果:
父类SuperClass init!
123
2.通过数组定义来引用类,不会触发此类的初始化
/**
* 被动使用类字段演示二:
* 通过数组定义来引用类,不会触发此类的初始化
**/
public class NotInitialization {
public static void main(String[] args) {
SuperClass[] sca = new SuperClass[10];
}
}
结果:
Process finished with exit code 0
3.常量在编译阶段会存入调用类的常量池中,本质上没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化
/**
*
* 常量在编译阶段会存入调用类的常量池中,本质上没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化
**/
public class ConstClass {
static {
System.out.println("ConstClass init!");
}
public static final String HELLOWORLD = "hello world";
}
结果:
hello world
接口类的加载
接口类加载与类大致相同,区别如下:
接口不要求父类全部初始化完毕;
接口不能使用static{}代码块;
最后
类的加载时机分为7个阶段,每个阶段都有详细的工作,当然除了加载和卸载其它阶段可能存在并行,而非顺序执行。这里只是简要介绍加载的相关引用问题,关于类加载器,再详细深入。
参考:
http://www.mamicode.com/info-detail-570611.html