第七章 类型的生命周期
1. 类型装载、链接与初始化
装载:将二进制形式的Java类型读入Java虚拟机中;
连接:将二进制形式的类型数据合并到迅即的运行时状态中去;
A. 验证:确保Java类型数据格式正确并且适用于Java虚拟机适用;
B. 准备:负责为该类型分配它所需的内存环境;(如类变量分配内存)
C. 解析:负责将常量池中的符号应用转换为直接引用;
初始化:给类变量赋予适当的初始值;
JVM严格定义了初始化的时机,所有的Java虚拟机实现必须在每个类或者接口的首次主动使用时初始化:
1. 当创建这个类的新实例时(或者通过字节码执行new指令,或者反射,克隆,反序列化)
2. 调用某个类的静态方法
3. 使用这个类或者接口的静态字段,或者是对这个字段赋值(final修饰的字段除外,编译阶段被初始化为常量表)
4. 当调用Java API 中的某些反射方法时,比如Class中的方法或者java.lang.reflect包中的方法
5. 当初始化某个类的子类时;
6. 当标明为启动类时(含main方法的那个类)
被动使用:父类中声明的字段被子类引用,在子类中调用父类这个变量时,是不是初始化自己的;
1. 装载
3个基本动作:a 通过该类型的完全限定名,产生一个代表该类型的二进制数据流
b 解析这个二进制数据流为方法区内的内部数据结构
c 创建一个表示该类型的java.lang.Class类的实例
2. 连接
验证: 确认类型符合Java语言的语义,并且他不会危及虚拟机的完整性(父类的装载(有的话),final的验证,符号引用的验证。。。)
准备: 为类变量分配内存空间,设置默认初始值
解析:将符号引用转化为直接引用的过程
3. 初始化:赋予正确的初始值
1) 如果类存在直接的超类,且还没有初始化的话,就先初始化超类(接口除外)
2) 如果类存在一个类初始化方法,就执行此方法
3) 初始化的过程是同步的
2. 对象的生命周期
1. 类的实例化:(4个方式,不多说了)
当Java虚拟机创建一个类的新实例时,不管是明确的还是隐含的,首先都需要在堆中为保存对象的实例变量分配内存,所有在对象的类中它的超类中声明的变量都要分配内存。
2. 垃圾回收和对象的终结
程序可以明确或者隐含地位对象分配内存,但是不能明确地释放内存。如果类声明了一个名为finalize()的返回void的方法,垃圾收集器会在释放这个实例所占据的内存空间之前执行这个方法(被称为终结方法)一次。垃圾收集器最多只会调用一个对象的终结方法一次(在对象变成不再被引用的之后的某个时候,在占据的对象被重用之前)。
3. 卸载类型
使用启动类装载器装载的类型永远是可触及的,所以永远不会被卸载,只有使用用户自定义类装载器装载的类型才会变成不可触及的。
判断动态装载的类型Class实例在正常的垃圾收集过程中是否可以触及有两种方式,第一,也是最明显的,如果程序保持对Class实例的明确引用,它就是可触及的。其次,如果在堆中还存在一个触及的对象,在方法区中它的类型数据指向一个Class实例,那么这个Class实例就是可触及的。