问题:类是如何加载的?
前言:
整篇博客都是围绕解决这个问题而展开.以问题为导向,并没有系统地阐释说明JVM体系.同时一些为个人不是特别成熟的理解,有误的话欢迎大神指正.
参考资料
深入理解Java虚拟机:JVM高级特性与最佳实践(第3版) 周志明
比较浅层的理解:
-
首先加载要创建对象的类及其父类
-
在类被加载的同时会将静态成员进行加载,主要包括静态成员变量的初始化,静态语句的执行.在加载时,安代码的先后顺序进行
-
需要的类加载完成后,开始创建对象,首先会加载非静态成员,主要包括非静态,成员变量的初始化,非静态成员变量的初始化,非静态语句块的执行,在加载时按代码先后顺序进行
-
最后执行构造器
JVM层面的理解:
1. 类的生命周期
加载->连接(验证->准备->解析)->初始化->使用->卸载
加载:
JVM虚拟机会将.class字节码文件加载进方法区.加载进方法区的是一个静态数据结构,并且是C++(instanceKlass)语言.JVM无法直接使用这个静态数据结构,所以会在堆区创建一个镜像,这个镜像其实就是Class对象(该对象在堆中).通过这个镜像来对方法区的数据结构进行访问
验证:
确保加载类的正确.(举例:把字节码文件的魔数修改以后,就会验证出错)
准备:
为类的静态变量(在方法区中,静态变量不属于类)分配内存,赋默认值.(这里的默认值是null,0这些,比如static int a=5;此时a还等于0)
final静态变量会直接赋值.final静态变量可以在编译时确定.所以就可以直接在这一阶段确定.放入常量池中,直接赋值
解析:
符号引用转为直接引用
举例:比如一个类中引用了其他类,在没到解析阶段中,字节码中的文件引用的是一个符号(即虚拟机不知道是那个类),虚拟机到解析这个阶段会把这个类的地址解析出来放进去.
初始化:
为类的静态变量赋初值,静态代码块执行
字节码有clinit用户初始化使用
init是实例构造器
JAVA内存区域
1. 程序计数器
用于指示执行行号,跟x86汇编语言的PC一样
2. JAVA虚拟机栈
线程私有的,存有方法的局部变量等.每个方法被执行时会创建栈帧,用完会弹出栈帧
3. 堆
存放了实例对象
4.方法区
存储已被虚拟机加载的类型信息,常量,静态变量
方法区中有运行时常量池 String类中的 intern可以使用
5.本地方法栈
和硬件的联系大一些