设计思路
在此处使用了3个类来验证继承关系中的初始化顺序:Father父类、Son子类和Demo类。父类和子类中各自包含了非静态代码区、静态代码区、静态成员、普通成员。运行时的主类为Test类,main()方法中创建了一个子类的对象,并且使用Father对象指向Son类实例的引用(父类对象指向子类引用,多态)。
代码块
Father父类
package com.qianfeng.boke;
//父类
public class Father {
{
System.out.println("父类非静态块 1执行");
}
static {
System.out.println("父类静态块1执行");
}
static Demo staticDemo1=new Demo("父类静态成员staticDemo01初始化");
Demo demo01=new Demo("父类普通成员demo01初始化");//用来做比较,运行程序时先运行谁
static Demo staticDemo02=new Demo("父类静态成员staticDemo02初始化");
static {
System.out.println("父类静态块2 执行");
}
public Father() {
System.out.println("父类默认构造函数被调用");
}
Demo demo02=new Demo("父类普通成员demo02 初始化");
{
System.out.println("父类非静态块2执行");
}
}
Son类继承Father类
package com.qianfeng.boke;
//子类
public class Son extends Father{
{
System.out.println("子类非静态块1执行");
}
static Demo staticDemoD1=new Demo("子类静态成员staticDemoD1初始化");
public Son() {
System.out.println("子类默认构造函数被调用");
}
Demo demo01=new Demo("子类普通成员demo01初始化");
static Demo staticDemoD2=new Demo("子类静态成员staticDemoD2初始化");
static {
System.out.println("子类静态块1 执行");
}
Demo demo02=new Demo("子类普通成员demo02初始化");
{
System.out.println("子类非静态块 2 执行");
}
static {
System.out.println("子类静态块2 执行");
}
}
Demo类
package com.qianfeng.boke;
public class Demo {
public Demo(String s) {
System.out.println(s);
}
public Demo() {
System.out.println("Demo默认构造函数被调用");
}
}
Test测试类
package com.qianfeng.boke;
public class Test {
public static void main(String[] args) {
Father father=new Son();
}
}
程序运行结果
父类静态成员staticDemo01初始化
父类静态成员staticDemo02初始化
父类静态块2 执行
子类静态成员staticDemoD1初始化
子类静态成员staticDemoD2初始化
子类静态块1 执行
子类静态块2 执行
父类非静态块 1执行
父类普通成员demo01初始化
父类普通成员demo02 初始化
父类非静态块2执行
父类默认构造函数被调用
子类非静态块1执行
子类普通成员demo01初始化
子类普通成员demo02初始化
子类非静态块 2 执行
子类默认构造函数被调用
继承关系中的初始化顺序的结论
(1)父类静态代码区和父类静态成员
(2)子类静态代码区和子类静态成员
(3)父类非静态代码区和普通成员
(4)父类构造函数
(5)子类非静态代码区和普通成员
(6)子类构造函数
继承的关系
初始化顺序在JVM中的解释
初始化顺序受到JVM类加载机制的控制,类加载机制包括加载、验证、准备、解析、初始化等步骤。不管是在继承还是非继承关系中,类的初始化顺序主要受到JVM类加载时机、解析和clinit()初始化规则的影响。
类解析在继承关系中的自下而上递归
类加载机制的解析阶段将常量池中的符号引用替换为直接引用,主要针对的是类或者接口、字段、类方法、方法类型、方法句柄和调用点限定符7类符号引用。而在字段解析、类方法解析、方法类型解析中,均遵循继承关系中自下而上递归搜索解析的规则,由于递归的特性(即数据结构中栈的“后进先出”),初始化的过程则是由上而下、从父类到子类的初始化顺序。