书接上回:
Java继承讲解(第二节)super和this用法的辨析-CSDN博客
本文结合Java代码块(code block)-CSDN博客一起阅读效果更好
继承关系上的执行顺序
在继承体系中,类的加载和对象的初始化都遵循一定的执行顺序。代码的执行顺序可以分为以下几个步骤:
1. 父类的静态代码块和静态变量(按声明顺序执行)
先执行父类中的静态代码块和静态变量的初始化。
2. 子类的静态代码块和静态变量(按声明顺序执行)
父类的静态代码块执行完后,再执行子类的静态代码块和静态变量。
3. 父类的实例代码块和构造方法
当对象被创建时,首先执行父类的实例代码块和构造方法。
4. 子类的实例代码块和构造方法
最后,执行子类的实例代码块和构造方法。
示例代码:
class Animal {
// 静态代码块(父类)
static {
System.out.println("静态代码块:Animal类加载");
}
// 实例初始化代码块(父类)
{
System.out.println("实例初始化代码块:Animal对象创建");
}
// 父类构造函数
public Animal() {
System.out.println("构造函数:Animal构造函数");
}
}
class Dog extends Animal {
// 静态代码块(子类)
static {
System.out.println("静态代码块:Dog类加载");
}
// 实例初始化代码块(子类)
{
System.out.println("实例初始化代码块:Dog对象创建");
}
// 子类构造函数
public Dog() {
System.out.println("构造函数:Dog构造函数");
}
}
public class Main {
public static void main(String[] args) {
System.out.println("创建第一个Dog对象");
Dog dog1 = new Dog(); // 创建第一个Dog对象
System.out.println("\n创建第二个Dog对象");
Dog dog2 = new Dog(); // 创建第二个Dog对象
}
}
运行结果:
创建第一个Dog对象
静态代码块:Animal类加载
静态代码块:Dog类加载
实例初始化代码块:Animal对象创建
构造函数:Animal构造函数
实例初始化代码块:Dog对象创建
构造函数:Dog构造函数
创建第二个Dog对象
实例初始化代码块:Animal对象创建
构造函数:Animal构造函数
实例初始化代码块:Dog对象创建
构造函数:Dog构造函数
解释:
-
静态代码块的执行:
- 在类加载时,首先执行父类
Animal
的静态代码块,然后执行子类Dog
的静态代码块。 - 静态代码块只执行一次,因此在程序运行的整个生命周期中,静态代码块只在类首次加载时执行。
- 在类加载时,首先执行父类
-
实例初始化代码块和构造方法的执行:
- 每次创建对象时,首先执行父类的实例初始化代码块,然后执行父类的构造方法。
- 接下来,执行子类的实例初始化代码块,最后执行子类的构造方法。
-
第二次创建对象时:
- 静态代码块不会再执行(因为类已经加载过了)。
- 再次按照父类实例初始化代码块 -> 父类构造方法 -> 子类实例初始化代码块 -> 子类构造方法的顺序执行。
总结继承关系中的代码块执行顺序
-
静态代码块和静态变量:
- 父类的静态代码块和静态变量先执行,子类的静态代码块和静态变量后执行。静态代码块在类加载时只执行一次。
-
实例初始化代码块和构造方法:
- 每次创建对象时,首先初始化父类的实例成员(包括实例初始化代码块和构造方法),然后初始化子类的实例成员。
-
执行顺序:
- 静态代码块(父类) -> 静态代码块(子类)
- 实例代码块(父类) -> 构造函数(父类)
- 实例代码块(子类) -> 构造函数(子类)
总结就是“父子父父子子”