JVM通过加载、连接和初始化一个Java类型,使该类型可以被正在运行的Java程序所使用。类型的生命周期如下图所示:
连接阶段又可以分为三个子步骤:验证、准备和解析。
(1)验证就是要确保java类型数据格式 的正确性,并适于JVM使用。
(2)准备阶段,JVM为静态变量分配内存空间,并设置默认值,注意,这里是设置默认值,比如说int型的变量会被赋予默认值0 。在这个阶段,JVM可能还会为一些数据结构分配内存,目的 是提高运行程序的性能,比如说方法表。
(3)解析过程就是在类型的常量池中寻找类、接口、字段和方法的符号引用,把这些符号引用替换成直接引用。这个阶段可以被推迟到初始化之后,当程序运行的过程中真正使用某个符号引用的时候 再去解析它。
类会在首次被“主动使用”时执行初始化,为类(静态)变量赋予正确的初始值。在Java代码中,一个正确的初始值是通过类变量初始化语句或者静态初始化块给出的。而我们这里所说的主动使用 包括:
(1)创建类的实例
(2)调用类的静态方法
(3)使用类的非常量静态字段
(4)调用Java API中的某些反射方法
(5)初始化某个类的子类
(6)含有main()方法的类启动时
初始化一个类包括两个步骤:
1、 如果类存在直接父类的话,且直接父类还没有被初始化,则先初始化其直接父类
2、 如果类存在一个初始化方法,就执行此方法
注:初始化接口并不需要初始化它的父接口。
类的初始化顺序:
普通类的初始化
public class InitBean {
public static void main(String[] args) {
System.out.println("main");
System.out.println("---实例化a---");
InitBean a=new InitBean();
System.out.println("---实例化b---");
InitBean b=new InitBean();
}
private static int i = 1;
public static String sStr = "我是静态变量";
public String iStr = "我是实例变量";
{
// 实例初始化块
System.out.println("进入实例初始化块");
System.out.println("实例初始化块中调用变量:" + iStr);
System.out.print("实例初始化块中调用方法:");
iTalk();
}
static {
// 静态初始化块
System.out.println("进入静态初始化块");
System.out.println("静态初始化块中调用变量:" + sStr);
System.out.print("静态初始化块中调用方法:");
sTalk();
}
public static void sTalk() {
// 静态方法
System.out.println("静态方法" + "/静态变量值" + (++i));
}
public void iTalk() {
// 实例方法
System.out.println("我是实例方法");
}
public InitBean() {
// 构造器
System.out.println("我是构造器");
}
}
执行结果
进入静态初始化块
静态初始化块中调用变量:我是静态变量
静态初始化块中调用方法:静态方法/静态变量值2
main
---实例化a---
进入实例初始化块
实例初始化块中调用变量:我是实例变量
实例初始化块中调用方法:我是实例方法
我是构造器
---实例化b---
进入实例初始化块
实例初始化块中调用变量:我是实例变量
实例初始化块中调用方法:我是实例方法
我是构造器
继承体系初始化父类
public class InitParent {
public static String sStr = "Parent静态变量";
public String iStr = "Parent实例变量";
{
// 实例初始化块
System.out.println("Parent进入实例初始化块");
System.out.println("Parent实例初始化块中调用变量:" + iStr);
System.out.print("Parent实例初始化块中调用方法:");
iTalk();
}
static {
// 静态初始化块
System.out.println("Parent进入静态初始化块");
System.out.println("Parent静态初始化块中调用变量:" + sStr);
System.out.print("Parent静态初始化块中调用方法:");
sTalk();
}
public static void sTalk() {
// 静态方法
System.out.println("Parent静态方法" + "/静态变量值" + (2));
}
public void iTalk() {
// 实例方法
System.out.println("Parent实例方法");
}
public InitParent() {
// 构造器
System.out.println("Parent构造器");
}
}
让InitBean继承自InitParent,执行结果
Parent进入静态初始化块
Parent静态初始化块中调用变量:Parent静态变量
Parent静态初始化块中调用方法:Parent静态方法/静态变量值2
进入静态初始化块
静态初始化块中调用变量:我是静态变量
静态初始化块中调用方法:静态方法/静态变量值2
main
---实例化a---
Parent进入实例初始化块
Parent实例初始化块中调用变量:Parent实例变量
Parent实例初始化块中调用方法:我是实例方法
Parent构造器
进入实例初始化块
实例初始化块中调用变量:我是实例变量
实例初始化块中调用方法:我是实例方法
我是构造器
---实例化b---
Parent进入实例初始化块
Parent实例初始化块中调用变量:Parent实例变量
Parent实例初始化块中调用方法:我是实例方法
Parent构造器
进入实例初始化块
实例初始化块中调用变量:我是实例变量
实例初始化块中调用方法:我是实例方法
我是构造器