Java虚拟机Class装在系统初探(一)之类的加载

  之前我们了解到,Class在java中经常以文件的形式存在,并且只有当被虚拟机装载的Class类型才能在程序中使用,系统装载类的过程可以划分为三个部分,加载,链接初始化。可以参考下图帮助理解,好有个大致的印象。


类的装载

像前面说的那样,java虚拟机并不会无条件的加载类,而是当一个类或者是接口在初次使用前就必须要进行初始化,这里的使用说的是“主动”使用,主动的情况有一下几种:

1.当创建一个类的实例的时候,比如说使用了new关键字,或者通过克隆,反射,或者是反序列化的操作。

2.当调用类的静态方法的时候,也就是说,我们使用的字节码invokestatic指令时。

3.当我们使用到类或者是接口中的静态字段时,不包含final所修饰的字段,回归到指令,体现为getstatic和putstatic的使用。

4.当我们使用java.lang.reflect包中的方法反射类的方法时,也会使得其主动加载类。

5.当初始化子类的时候,按照之前了解的内容,子类的初始化必须先初始化父类,所以,此时会加载相应的父类进行加载。

6.作为虚拟机启动的main()方法,如果此类包含main()方法,则这个类会加载到虚拟机中。

参考下面的例子来体会下:

父类:

public class Parent {

	static {
		System.out.println("Parent init");
	}
}

子类:

public class Child extends Parent{
	static{
		System.out.println("Child init");
	}
}

主函数类:

public class InitMain {

	public static void main(String[] args){
		Child c = new Child();
	}
}

运行结果:


可以看到,符合我们的预期,同时证明了两个条件,条件一和条件五。那我们改在一下,来一个“被动”的例子:

修改下父类,子类不变:

public class Parent {

	static {
		System.out.println("Parent init");
	}
	
	public static int v = 100;
}

修改下主函数类:

public class InitMain {

	public static void main(String[] args){
		System.out.println(Child.v);
	}
}

执行结果:如下:


可以看到,这里是通过子类访问的父类,但是,这里解释为,Child类并没有被初始化,而只有Parent父类被初始化,如果我们使用-XX:+TraceClassLoading参数运行,得到以下日志:


可以看到,类都被加载了,但是只有父类被初始化了,子类并没有被初始化,但是需要强调的是,这两个类都已经被jvm加载,这个同时验证了第五条的情形。

再来举一个例子,验证一下final常量的引用,看一下有什么不同。

public class FinalFiledC {

	public static final String constString = "COnNST";
	static{
		System.out.println("FinalFieldC init");
	}
}

测试主函数类:

public class UseFinalField {
	public static void main(String[] args){
		System.out.println(FinalFiledC.constString);
	}

}

运行结果为:CoNST;

表面上看不出什么,那让我们打印一下其类的加载的日志:


  可以看到,类根本不会被加载到系统中,而是直接接我们要使用的final字段量存放到常量池中,并没有引用FinalFieldC类,可以发现,在javac进行编译的时候,直接植入目标了类,不再使用引用类获取final修饰的字段常量。

   其实加载类除以第一个阶段,加载类的时候Java虚拟机必须完成下面的工作:

通过类的全名获取二进制数据流,解析类的二进制数据流为方法区内的数据结构,并创建java.lang.Class类的实例标识该类型。二进制数据流来源较广,一般的可以读取一个后缀为.class的文件,或者也可以读入jar,zip等,也可以通过Http协议通过网络进行加载,这类似于之前的Jsp的使用,下载到本地的class文件再进行执行。

到这里,关于类的加载我们了解了其加载的条件,已经走了第一步,接下来会做什么呢,按照上面的流程图我们需要到链接部分了,下一节将讲述类在连接部分进行了哪些操作。

猜你喜欢

转载自blog.csdn.net/qq_18870127/article/details/80487099