1. Java继承机制深度解析:从构造方法到传参机制
Java继承是面向对象编程中最基础也最容易踩坑的特性之一。很多初学者在面试中被问到"子类实例化时父类构造方法如何调用"、"静态代码块和实例代码块的执行顺序"这类问题时往往语焉不详。今天我们就用实际代码拆解继承中的三个核心机制:构造方法调用链、代码块执行顺序和传参机制,这些知识点在Spring框架的Bean初始化、MyBatis的Mapper代理等实际场景中都有广泛应用。
我在处理一个线上事故时曾遇到过一个典型问题:子类重写了父类方法,但在父类构造方法中调用了这个可被重写的方法,导致子类实例化时出现NPE。这个案例让我意识到,不理解继承的底层机制,写出来的代码就是埋雷。下面我们通过三个递进层次,彻底掌握Java继承的核心逻辑。
1.1 构造方法调用链的底层原理
Java中子类实例化时必定会调用父类构造方法,这是语言规范强制要求的。但为什么要有这个限制?其实这是为了保证对象初始化的完整性。想象你组装一台电脑,必须先装好主板(父类初始化)才能安装显卡(子类初始化)。
java复制class Parent {
Parent() {
System.out.println("Parent Constructor");
}
}
class Child extends Parent {
Child() {
// 编译器会自动插入super()
System.out.println("Child Constructor");
}
}
执行new Child()时会输出:
code复制Parent Constructor
Child Constructor
这里有个关键细节:如果父类没有无参构造方法,必须在子类构造方法第一行显式调用super(参数)。我在代码审查时经常看到这样的错误:
java复制class Parent {
Parent(String name) {...}
}
class Child extends Parent {
Child() {
// 编译错误,缺少super(name)
System.out.println("Child Constructor");
}
}
重要提示:在Spring框架中,这个机制会影响Bean的初始化顺序。比如父Bean和子Bean的依赖注入顺序就遵循这个规则。
1.2 代码块执行顺序的实战分析
代码块执行顺序是面试高频考点,也是实际项目容易出错的地方。先看一个包含所有类型代码块的例子:
java复制class Parent {
static { System.out.println("Parent static block"); }
{ System.out.println("Parent instance block"); }
Parent() { System.out.println("Parent constructor"); }
}
class Child extends Parent {
static { System.out.println("Child static block"); }
{ System.out.println("Child instance block"); }
Child() { System.out.println("Child constructor"); }
}
执行new Child()的输出顺序是:
code复制Parent static block
Child static block
Parent instance block
Parent constructor
Child instance block
Child constructor
这个顺序可以总结为:
- 父类静态代码块(类加载时执行)
- 子类静态代码块(类加载时执行)
- 父类实例代码块(每次实例化执行)
- 父类构造方法
- 子类实例代码块
- 子类构造方法
我在金融项目中曾遇到一个内存泄漏问题:在静态代码块中初始化了大量缓存数据,却忘记考虑类卸载的情况。这提醒我们:静态代码块要慎用,特别是涉及资源初始化的场景。
1.3 传参机制的陷阱与解决方案
继承中的传参机制最容易产生隐蔽bug。看这个典型例子:
java复制class Parent {
protected String value;
Parent(String value) {
this.value = value;
printValue();
}
void printValue() {
Sy
