类的加载过程---jvm
类加载共有以下步骤,如图:
clipboard.png
1.加载:
把class文件读入虚拟机,转换成为运行时数据结构,也就是InstanceClass,InstanceClass是C++实现的JVM中表示一个java Class的,同时java class文件中的每个方法也会转换为C++的Method对象.
记住:
1>.C++也是面向对象的,它也有类和对象的概念
2>.还有一件事就是把元信息保存到方法区里,也就是诸如方法的字节码指令
- 验证:
验证的目的是为了确保Class文件的字节流中的信息不会危害到虚拟机;
文件格式验证 :验证字节流是否符合Class文件的规范,如主次版本号是否在当前虚拟机范围内,常量池中的常量是否有不被支持的类型等等;
元数据验证 :对字节码描述的信息进行语义分析,如这个类是否有父类,是否继承了不被继承的类等等;
字节码验证 :通过验证数据流和控制流的分析,确定程序语义是否正确,主要针对方法体的验证。如:方法中的类型转换是否正确,跳转指令是否正确等等;
符号引用验证 :为了确保解析动作能正确执行;
- 准备:
简单理解就是给static成员分配空间,已经赋值,注意是零值。比如int是0,long是0L。
4 .解析:
符号引用替换为直接引用。就是说我要执行一个方法,字节码一般都是这么个格式的invokevirtual #7。其中#7是常量表的第七个常量。但是这个常量只是一个字面量,实际代码要能够找到它要执行的方法的地址,解析就是干这个的
- 初始化:
这个步骤才是执行我们自己写的代码的阶段了。如果一个类里有static成员或者static代码块,编译器变出来的class文件会自动多出来一个clinit方法,也就是说对于static成员的赋值是在这里做的。
初始化:在准备阶段已经对类变量进行初始化了,这里的初始化是执行类构造器<clinit>。
<clinit>()方法是编译器自动收集类中所有类变量的赋值动作和静态代码块而产生的方法(无论类变量和静态代码块的位置是什么样,都是先执行类变量的赋值动作,再执行静态代码块) 这里特别需要注意的是,初始化只是执行clinit而不是init,加载class并不是创建一个对象