解释下多态?
1 个回答
不要和差点意思的人周旋。蔡琳# 什么是多态 “同一接口,不同实现;**父类/接口类型引用**指向**子类对象**,调用被**子类重写**后的方法,表现出不同行为。” 核心是 **运行时多态(method overriding + 动态绑定)**。 成立条件(4 件套): 1. 继承/实现(class 继承或 implements interface) 2. 方法 **重写**(`@Override`,签名一致) 3. **向上转型**:`Parent p = new Child();` 4. **动态分派**:调用 `p.method()` 时按 **实际对象类型** 决定运行哪版方法 # Java 中三种常见“多态”形态 1. **子类型多态(运行时多态,最常说的那个)** * 通过 **重写** 实现;**单分派**:只看“接收者(this)”的运行时类型。 2. **重载(编译时多态/Ad-hoc)** * 同名不同参;**在编译期**按 **形参静态类型** 选定目标方法。 3. **泛型多态(参数化多态)** * `List<String>` / `List<Integer>` 用同一套代码;Java 采用**类型擦除**,运行期两者是同一原生类型。 # 最小演示(覆盖 vs 重载) ```java class Animal { void speak() { System.out.println("A"); } } class Dog extends Animal { @Override void speak() { System.out.println("D"); } } public class Demo { static void call(Animal a) { a.speak(); } // ① static void call(Dog d) { System.out.println("OL-D"); } // ② 重载 public static void main(String[] args) { Animal x = new Dog(); x.speak(); // 输出 D —— 覆盖 + 运行时分派(看对象实际类型) call(x); // 输出 A 或 D? 选中哪个 call? // 先做“重载决议”:x 的静态类型是 Animal,匹配到 ①, // 然后在 ① 内再次动态分派 a.speak() → D } } ``` 结论:**重载先于运行时分派**,重载只看**静态类型**;覆盖看**运行时类型**。 再看一个“`null` 重载”坑: ```java static void f(Object o) { System.out.println("O"); } static void f(String s) { System.out.println("S"); } f(null); // 输出 S(更具体的重载被选中) ``` # 不能参与多态/或特殊规则 * `static` / `private` / `final` 方法 **不参与覆盖**(`static` 是隐藏/遮蔽)。 * **字段(属性)不多态**:`p.field` 看的是引用的静态类型。 * **构造器**不能被继承/覆盖。 * `final` 类/方法禁止被重写(如 `String`)。 * CGLIB 代理无法拦截 `final` 方法(和 AOP 相关)。 # 泛型与多态的补充 * 泛型在编译期提供类型检查,**运行时类型擦除**:`List<String>` 与 `List<Integer>` 运行期都是 `List`。 * 上界/下界配合协变/逆变语义:`List<? extends Number>` 只读安全;`List<? super Integer>` 可写入 `Integer`。 # 什么时候用多态(工程实践) * **面向接口编程**:入参、字段、返回值尽量用接口/父类(如 `List`、`Map`、`OutputStream`)。 * **解耦分支**:策略模式、模板方法、状态机——把 `if-else` 变成多态分发。 * **可替换实现**:测试用 mock、运行时切换实现(本地/远程、同步/异步)。 # 面试常问的几句“要点回答” * 多态=**向上转型 + 覆盖 + 动态绑定**,Java 是**单分派**语言。 * **重载是编译期决议**,**覆盖是运行期决议**。 * `static/private/final/字段` 不参与运行时多态。 * 泛型是**参数化多态**,Java 运行期**类型擦除**。发布于 2025-08-19 07:47 •IP属地 贵州举报评论收藏
公众号进入网站体验更佳

