JAVA 类从被加载到虚拟机内存开始到卸载出内存为止, 它的生命周期包括了以下几个步骤:加载,验证,准备,解析,初始化,使用,卸载。其中验证,准备和解析统称为链接过程。发生的顺序如下下图所示:
上图中,加载,验证,准备,初始化和卸载这几个步骤是确定的,类加载过程必须按照这个过程进行,然而解析阶段则不一定,它在目中情况下可以在初始化阶段之后再开始,这是为类支持java语言的动态绑定。
1:什么时候会触发类加载?
java虚拟机规范中并没有进行强制的约束,但是对于初始化阶段,虚拟机规范严格的规定有且只有5中情况,必须立即对类进行初始化(加载,验证,准备在此之前完成) .
1):遇到new,getstatic,putstatic,invokestatic这四条字节码指令时。如果类没有进行过初始化,则必须触发其初始化。这是条指令最长见的场景是。使用new操作,设置和获取类的静态字段(被final修饰的字段除外,已在编译期将其放入常量池中的字段除外).以及调用类的静态方法时。
2): 使用reflect包中的方法对类进行反射调用的的时候,如果类中没有经过初始化,则需要先触发其初始化。
3): 初始化一个类的时候,如果其父类还没有进行初始化是,则需要先触发其父类的初始化。
4): 当虚拟机启动时,用户需要制定一个要执行的主类(包含main方法的类)虚拟机会先初始化这个主类。
5): 使用JDK1.7动态语言支持时,如果一个MethodHandle实例最后解析的结果REF_getStatic, REF_putStatic,REF_invokeStatic 的方法和句柄,并且这个方法的所对应的类没有初始化,会先触发这个类的初始化。
1:本次主要讨论第一种情况,new,getstatic,putstatic,invokestatic字节码
package cn.zjdyms.classloader;
//显示类加载的过程需要添加虚拟机参数-XX:+TraceClassLoader/-verbose:class
public class Loading {
public static void main(String[] args) throws InterruptedException {
//Thread.sleep(5000);
System.out.println("------------------");
/*new NewLoader();
System.out.println(LoadingInner.i);
System.out.println(LoadingInner2.j);
System.out.println(GetLoader.STR);
SetLoader.STR = "ss";
StaticMethod.say();*/
}
static class LoadingInner{
public static final int i = 0;
public static int j = 0;
}
static class LoadingInner2{
public static int j = 0;
}
static class NewLoader{
}
static class GetLoader{
static String STR = "abcd";
}
static class SetLoader{
static String STR = "defg";
}
static class StaticMethod{
public static void say() {
System.out.println("helloWorld");
}
}
}
注释有加上时:打印输出
字节指令: 暂时不存在调用上述内部类的指令。
去除main方法中的注释,中间加载几个内部类但是没有加载LoadingInner类。
字节码指令:从字节码中可以看出为什么没有加载LoadingInner类。取值直接使用的iconst_0取得LoadingInner中的i值。是final修饰的字段并且是静态字段。
剩余的指令就不做一一介绍了。
package cn.zjdym.learn;
public class StaticTest
{
public static void main(String[] args)
{
staticFunction();
}
static StaticTest st = new StaticTest();
static
{
System.out.println("1");
}
{
System.out.println("2");
}
StaticTest()
{
System.out.println("3");
System.out.println("a="+a+",b="+b);
}
public static void staticFunction(){
System.out.println("4");
}
int a=110;
static int b =112;
}
上面的方法的具体的输出有兴趣的可以自行测试。下次的详解。