简述Java类的生命周期
首先,我们需要知道对象的生命周期和类的生命周期并不是一回事,因为在创建对象之前,会触发类的加载
,在对象被jvm垃圾回收器回收后,jvm才有可能准备对类进行卸载
。所以类的整个生命周期要比对象的生命周期长的多。
一个java类的完整的生命周期会经历加载、连接、初始化、使用、和卸载
五个阶段,连接里面具体分的话,连接里验证、准备、解析
三个环节,如图所示:
注意:一般来说,我们听得比较多的类加载
和这里的加载
并不是一回事,通常我们说类加载
指的是类的生命周期中加载、连接、初始化
三个阶段。
首先我们顺便了解一下一段java代码在程序运行期间会经历三个阶段: source-->class-->runtime
,根据来简单理解类的完整生命感觉大体上就能够明白许多,如图所示:
1.加载:
- 就是指将class文件读入内存,并为之创建一个Class对象。
- 任何类被使用时系统都会建立一个Class对象。
**注意:
1.加载说白了就是从source阶段->class阶段;
2.我们所说的反射,即解剖一个类的各个组成部分,就是说在java中用一个Class对象来表示一个java类的class阶段。**
2.连接:
- 验证:是否有正确的内部结构,并和其他类协调一致
- 准备:负责为类的静态成员分配内存,并设置默认初始化值
- 解析:将类的二进制数据中的符号引用替换为直接引用
简单说:加载的主要任务就是在类阶段做一些加载后的验证工作以及一些初始化前的准备工作
3.初始化:
- 创建类的实例,即new对象
- 访问或者设置类的静态变量,调用类的静态方法
- 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
- 初始化某个类的子类,会触发父类的初始化
- 直接使用java.exe命令来运行某个主类,也就是直接调用main方法
class Fu{
static {
System.out.println("Fu");
}
public static String a = null;
public static void method(){}
}
class Zi extends Fu{}
//Test测试一下:main方法运行会初始化类
public static void main(String[] args){
new Fu();//new对象 引发初始化
Fu.a = "";//设置静态变量
String a = Fu.a;//访问静态变量
Fu.method();//调用静态方法
Class clazz = Fu.class;//通过反射进行上述操作
//......各种上述操作
new Zi();//new子类引发父类的初始化
}
4.使用:
- 使用阶段包括主动引用和被动引用,
主动引用
会引起类的初始化,而被动引用
不会引起类的初始化。 - 主动引用:上面3所讲的初始化的那几种方式。
- 被动引用:①引用父类的静态字段,只会引起父类的初始化,而不会引起子类的初始化。②定义类数组,不会引起类的初始化。③引用类的常量,不会引起类的初始化。
class Fu{
static {
System.out.println("初始化Fu");
}
public static String a = null;
public final static String b = "b";
}
class Zi extends Fu{
static {
System.out.println("初始化Zi");
}
}
//Test测试一下
String a = Zi.a;//引用父类的静态字段,只会引起父类初始化,而不会引起子类的初始化
String b = Fu.b;// 使用类的常量不会引起类的初始化
Zi[] sc = new Zi[10];// 定义类数组不会引起类的初始化
5.卸载:
在类使用完之后,如果满足下面的情况,类就会被卸载:
- 该类
所有的实例
都已经被回收,也就是java堆中不存在该类的任何实例。 - 加载该类的ClassLoader(类加载器)已经被回收。
- 该类对应的java.lang.Class对象没有任何地方被引用,无法在任何地方通过反射访问该类的方法。
(这句话我我认为就是该类对应的class对象也被回收)
所以,卸载就好像类加载过程反着来一样,先把该类的实例回收,再把该类对应的class对象回收,再把类加载器回收,即一个类一般满足上面的三个条件才会被jvm回收,而对象不使用jvm就会立刻回收。
补充类加载器的组成:
(1) Bootstrap ClassLoader 根类加载器
也被称为引导类加载器,负责Java核心类的加载
。比如System,String等。在JDK中JRE的lib目录下rt.jar文件中
(2)Extension ClassLoader 扩展类加载器负责JRE的扩展目录中jar包的加载
。在JDK中JRE的lib目录下ext目录
(3)Sysetm ClassLoader 系统类加载器负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径