**多态(Polymorphism)**是面向对象编程的三大特性之一(封装、继承、多态),分为编译时多态(静态多态)和运行时多态(动态多态),
编译时多态
编译时多态是指在编译阶段确定具体执行哪个方法。它主要通过方法重载(Overloading) 实现。
在同一个类中,有多个方法具有相同的名称但参数列表不同(参数类型、参数个数或参数顺序不同)
运行时多态
运行时多态是指在程序运行期间确定具体执行哪个方法。它主要通过方法重写(Overriding) 和 接口(Interface) / 继承(Inheritance) 实现,并且需要结合向上转型(Upcasting)和动态绑定(Dynamic Binding)。
转型与绑定
向下转型(Downcasting)指将父类对象的引用 赋值给子类类型的变量 (如 Dog dog = (Dog) animal;)
向上转型(Upcasting)是指将子类对象的引用 赋值给父类类型的变量 (如 Animal animal = new Dog();)。
向上转型是多态性的重要体现,其作用在于以统一的父类类型处理不同的子类对象(即同继承链),提高代码灵活性。
向上转型时,实际对象在内存中的结构保持不变(即保留完整子类所有字段和方法),父类引用仅作为访问对象的"视图窗口"(可以理解为只是代码层面的标识变了,对象本身没变)。
向上转型后,调用父类方法,但实际执行的是子类覆盖或继承的方法(动态绑定)。
向上转型后,无法通过调用子类特有的方法,即便是父类中有同名抽象方法也不行。
⚠️ 注意:在一些早期的 Java 版本中,虚拟机可能允许在父类引用变量上调用子类的特定方法,但这是不被推荐的,并且已经被更严格的 Java 规范所取代
绑定(Binding)指的是方法调用(Call)绑定到方法体(Implementation) ,分为静态绑定(Static Binding)和动态绑定(Dynamic Binding)。
| 特性 | 静态绑定 | 动态绑定 |
|---|---|---|
| 绑定时机 | 编译期 | 运行期 |
| 绑定方法 | 绑定到编译时声明类型的方法 | 绑定到实际对象类型的方法 |
| 方法类型 | private/static/final/构造方法 | 可重写的实例方法 |
java
// 抽象父类
abstract class Parent {
// 具体方法 - 可被子类重写
public void f1() {
System.out.println("Parent's f1");
}
// 抽象方法 - 必须由子类实现
public abstract void f2();
// 静态方法 - 不能被重写,只会被隐藏
public static void staticMethod() {
System.out.println("Parent's static method");
}
// 最终方法 - 禁止子类重写
public final void finalMethod() {
System.out.println("Parent's final method (cannot be overridden)");
}
// 私有方法 - 不能被子类重写或访问
private void privateMethod() {
System.out.println("Parent's private method (only accessible within Parent)");
}
// 受保护方法 - 可被子类重写
protected void protectedMethod() {
System.out.println("Parent's protected method (can be overridden)");
}
}
// 子类
class Child extends Parent {
// 重写父类方法 - 动态绑定
@Override
public void f1() {
System.out.println("Child's overridden f1");
}
// 实现父类抽象方法 - 动态绑定
@Override
public void f2() {
System.out.println("Child's implementation of f2");
}
// 子类特有方法 - 父类引用无法访问
public void f3() {
System.out.println("Child's specific method f3");
}
// 隐藏父类的静态方法 - 静态绑定
public static void staticMethod() {
System.out.println("Child's static method (hiding parent's)");
}
// 尝试重写 final 方法会导致编译错误
// @Override
// public void finalMethod() {
// System.out.println("This would cause an error");
// }
// 尝试"重写"父类 private 方法 - 实际上是新方法
private void privateMethod() {
System.out.println("Child's private method (not overriding)");
}
// 重写父类的 protected 方法
@Override
protected void protectedMethod() {
System.out.println("Child's overridden protected method");
}
}
public class Main {
public static void main(String[] args) {
// 向上转型:Parent引用指向Child对象
Parent p = new Child();
System.out.println("=== 动态绑定演示 ===");
p.f1(); // 输出: "Child's overridden f1" - 动态绑定
p.f2(); // 输出: "Child's implementation of f2" - 动态绑定
p.protectedMethod(); // 输出: "Child's overridden protected method" - 动态绑定
System.out.println("\n=== 私有方法行为演示 ===");
p.callPrivate(); // 输出: "Child calling: Child's private method" - 调用子类重写的callPrivate
System.out.println("\n=== 父类私有方法隔离演示 ===");
Parent realParent = new Parent() {
@Override
public void f2() {
System.out.println("Anonymous implementation of f2");
}
};
realParent.callPrivate(); // 输出: "Parent calling: Parent's private method" - 调用父类私有方法
System.out.println("\n=== 静态方法调用演示 ===");
p.staticMethod(); // 输出: "Parent's static method" - 静态绑定
Child.staticMethod(); // 输出: "Child's static method" - 直接调用
System.out.println("\n=== Final方法调用演示 ===");
p.finalMethod(); // 输出: "Parent's final method" - 不可重写
System.out.println("\n=== 子类特有方法访问限制 ===");
// p.f3(); // 编译错误:Parent类型中没有f3方法
System.out.println("\n=== 向下转型演示 ===");
if (p instanceof Child) {
Child c = (Child) p; // 安全的向下转型
c.f3(); // 输出: "Child's specific method f3" - 成功调用
c.staticMethod(); // 输出: "Child's static method" - 但编译器会警告
}
System.out.println("\n=== 静态绑定与动态绑定对比 ===");
Parent.staticMethod(); // 静态绑定:Parent's static method
Child.staticMethod(); // 静态绑定:Child's static method
System.out.println("\n=== 私有方法隔离性验证 ===");
Child child = new Child();
// child.privateMethod(); // 编译错误:privateMethod()在Child中不可见
// 只能在Child类内部访问privateMethod
System.out.println("\n=== 方法调用类型总结 ===");
try {
System.out.println("f1()调用类型: " +
(p.getClass().getMethod("f1").isBridge() ? "桥方法" : "普通虚方法"));
System.out.println("privateMethod()可见性: " +
(p.getClass().getDeclaredMethod("privateMethod") != null ? "存在但不可访问" : "不存在"));
} catch (NoSuchMethodException e) {
System.out.println("无法通过反射访问privateMethod: " + e.getMessage());
}
}
}
接口与抽象类
| 特性 | 接口 (Interface) | 抽象类 (Abstract Class) |
|---|---|---|
| 实现/继承方式 | 多实现 (implements) |
单继承 (extends) |
| 方法实现 | 默认隐式 public abstract Java 8+ 支持 default 默认方法和 static 静态方法进行实现 |
自由混合抽象方法和具体实现方法 |
| 成员变量 | 只能是 public static final 常量 |
任意成员变量(普通/静态/常量) |
| 构造方法 | ❌ 不允许 | ✅ 可定义构造方法 |
| 方法访问修饰符 | 隐式 public (Java 9+ 可 private) |
任意访问修饰符 |
| 设计目的 | 定义行为契约("能做什么") | 提供基础实现("是什么")基于接口的策略模式(Strategy Pattern) |
基于"接口 + 组合"的策略模式(Strategy Pattern),定义策略接口,继而由具体策略类提供具体算法实现,而上下文(Context)持有一个策略对象的引用,通过组合动态切换策略。
基于"抽象类 + 继承"的模板方法模式(Template Method Pattern),就是在抽象类定义算法的骨架,将某些步骤延迟到子类实现。
类生命周期
- 类加载机制:加载(Loading) -> 链接(Linking) -> 初始化(Initialization)
- 类使用阶段:实例化 (Instantiation) -> 方法调用 / 字段访问 /反射操作等
- 类生命周期:类加载机制 -> 使用阶段(Using) -> 卸载(Unloading)
否 否 是 是 开始创建子类B实例 父类A是否已加载? 加载父类A 初始化父类A静态变量 执行父类A静态块 子类B是否已加载? 加载子类B 初始化子类B静态变量 执行子类B静态块 分配堆内存空间 初始化父类A实例变量 执行父类A实例初始化块 执行父类A构造器 初始化子类B实例变量 执行子类B实例初始化块 执行子类B构造器 对象创建完成 第二次创建B实例 分配堆内存空间
java
class A {
// 静态变量
private static String staticFieldA = initStaticField("A类静态变量");
// 静态初始化块
static {
System.out.println("A类静态初始化块");
}
// 实例变量
private String instanceFieldA = initInstanceField("A类实例变量");
// 实例初始化块
{
System.out.println("A类实例初始化块");
}
// 构造器
public A() {
System.out.println("A类构造器");
}
// 辅助初始化方法
private static String initStaticField(String msg) {
System.out.println(msg);
return "";
}
private String initInstanceField(String msg) {
System.out.println(msg);
return "";
}
}
class B extends A {
// 静态变量
private static String staticFieldB = initStaticField("B类静态变量");
// 静态初始化块
static {
System.out.println("B类静态初始化块");
}
// 实例变量
private String instanceFieldB = initInstanceField("B类实例变量");
// 实例初始化块
{
System.out.println("B类实例初始化块");
}
// 构造器
public B() {
System.out.println("B类构造器");
}
// 辅助初始化方法(与父类同名但独立)
private static String initStaticField(String msg) {
System.out.println(msg);
return "";
}
private String initInstanceField(String msg) {
System.out.println(msg);
return "";
}
}
public class InitializationOrder {
public static void main(String[] args) {
System.out.println("--- 第一次创建B实例 ---");
new B();
System.out.println("\n--- 第二次创建B实例 ---");
new B();
}
}
log
--- 第一次创建B实例 ---
A类静态变量
A类静态初始化块
B类静态变量
B类静态初始化块
A类实例变量
A类实例初始化块
A类构造器
B类实例变量
B类实例初始化块
B类构造器
--- 第二次创建B实例 ---
A类实例变量
A类实例初始化块
A类构造器
B类实例变量
B类实例初始化块
B类构造器