面试题答案
一键面试加载(Loading)阶段
- 特点:
- 查找并加载字节码:Java虚拟机(JVM)通过类加载器在文件系统、网络等位置查找抽象类对应的字节码文件(
.class
文件),并将字节码读入内存。 - 创建类的二进制表示:将字节码转换为JVM能够理解的内部数据结构,这个二进制表示包含类的元数据信息,如类名、父类、接口、字段、方法等。
- 分配内存:为类的静态变量(
static
修饰的变量)在方法区分配内存空间,并赋予初始值(零值或默认值,如int
为0,boolean
为false
等)。
- 查找并加载字节码:Java虚拟机(JVM)通过类加载器在文件系统、网络等位置查找抽象类对应的字节码文件(
连接(Linking)阶段
- 验证(Verification):
- 特点:
- 文件格式验证:确保字节码文件格式符合JVM规范,例如检查魔数、版本号等是否正确,保证字节码可以被JVM安全加载。
- 元数据验证:对类的元数据进行语义检查,比如检查类是否继承了不允许继承的类(如
final
类),字段和方法是否与父类冲突等。 - 字节码验证:对字节码进行数据流和控制流分析,确保字节码指令合法且不会导致非法操作,如检查跳转指令是否指向合法位置,操作数栈是否溢出等。
- 符号引用验证:确保类对其他类、字段、方法的符号引用在解析阶段可以成功转换为直接引用,检查符号引用所指向的目标是否存在等。
- 特点:
- 准备(Preparation):
- 特点:正式为类的静态变量分配内存并设置初始值,这个阶段的初始值是数据类型的零值或默认值。例如,对于
static int num;
,num
被初始化为0 。对于static final
修饰的基本数据类型和字符串常量,在这个阶段会赋予真正的初始值。例如static final int num = 10;
,num
会在准备阶段就被赋值为10。
- 特点:正式为类的静态变量分配内存并设置初始值,这个阶段的初始值是数据类型的零值或默认值。例如,对于
- 解析(Resolution):
- 特点:将类的符号引用转换为直接引用。符号引用是以一组符号来描述所引用的目标,在编译时并不知道所引用目标的实际内存地址。而直接引用是直接指向目标的指针、相对偏移量或者句柄等。例如,类对其他类、接口、字段、方法的引用,在解析阶段会找到这些目标的实际内存位置,使得JVM可以直接访问它们。
初始化(Initialization)阶段
- 特点:
- 执行静态代码块和静态变量赋值:按照在源文件中出现的顺序,执行类的静态代码块(
static {...}
)和静态变量的显式赋值操作。例如:
- 执行静态代码块和静态变量赋值:按照在源文件中出现的顺序,执行类的静态代码块(
public abstract class AbstractClass {
static int num = 5;
static {
num = num + 10;
}
}
在初始化阶段,先给num
赋值为5,然后执行静态代码块,num
变为15。
- 调用父类的初始化方法:如果该抽象类有父类,会先调用父类的初始化方法,确保父类的静态变量和静态代码块先执行,保证继承体系的正确初始化。
使用(Using)阶段
- 特点:
- 类的实例化和方法调用:可以使用这个抽象类(通过其子类实例化等方式间接使用),例如子类可以继承该抽象类并实现其抽象方法,然后创建子类实例调用方法。抽象类中的非抽象方法也可以被其子类直接调用。
- 访问静态成员:可以直接访问抽象类的静态成员(静态变量和静态方法),这些静态成员在内存中的数据会随着程序的运行而发生变化。
卸载(Unloading)阶段
- 特点:
- 类加载器回收:当类加载器被回收时(例如加载该抽象类的自定义类加载器不再被引用),该类加载器所加载的类(包括抽象类)也会被卸载。
- 内存释放:类的二进制表示从方法区中移除,类的静态变量所占用的内存空间被释放,类的实例(如果存在,通过子类实例化等方式产生的实例)所占用的堆内存也会在合适的时候(对象不再被引用)被垃圾回收器回收。
- 资源清理:如果抽象类在加载或使用过程中打开了一些资源(如文件句柄、数据库连接等),需要在卸载前进行资源清理,确保资源正确关闭,避免资源泄漏。