【从零开始java学习|第十六篇】什么是多态

【从零开始java学习|第十六篇】什么是多态

目录

一、什么是多态

多态的实现前提

二、多态调用成员的特点

1. 调用成员变量的特点:编译看左边,运行也看左边

2. 调用成员方法的特点:编译看左边,运行看右边

关键对比总结

三、多态的优势和弊端

1. 多态的优势(为什么必须掌握多态)

(1)提高代码的扩展性

(2)提高代码的复用性

(3)简化代码逻辑

2. 多态的弊端(为什么需要类型强转)

四、多态弊端的解决方法:类型强转

1. 类型强转的语法

2. 强转的风险:ClassCastException

3. 安全强转:先判断后转换(instanceof 关键字)

instanceof 的语法

instanceof 的核心作用

五、多态的典型应用场景

六、多态高频面试题整理

七、总结

一、什么是多态

多态是 Java 面向对象三大特性(封装、继承、多态)的核心之一,指同一行为(方法调用)在不同对象上表现出不同的实现效果。简单来说,就是 “一个接口,多种实现”。

多态的实现前提

存在继承关系:多态发生在父类与子类之间(包括直接继承和间接继承);子类重写父类方法:子类对父类的非静态方法进行重写(Override),这是多态的核心载体;父类引用指向子类对象:通过父类类型 变量名 = new 子类类型()的形式,建立多态引用。

示例:多态的基本实现

// 父类:定义统一行为标准

class Animal {

public void move() {

System.out.println("动物在移动");

}

}

// 子类1:重写父类方法,实现特有行为

class Dog extends Animal {

@Override

public void move() {

System.out.println("狗在奔跑");

}

}

// 子类2:重写父类方法,实现另一特有行为

class Bird extends Animal {

@Override

public void move() {

System.out.println("鸟在飞翔");

}

}

public class PolymorphismDemo {

public static void main(String[] args) {

// 父类引用指向子类对象(多态引用)

Animal animal1 = new Dog();

Animal animal2 = new Bird();

// 同一方法调用,表现出不同行为(多态效果)

animal1.move(); // 输出:狗在奔跑

animal2.move(); // 输出:鸟在飞翔

}

}

二、多态调用成员的特点

多态中,成员变量和成员方法的调用遵循截然不同的规则,核心区别在于 “成员方法支持多态,成员变量不支持多态”。

1. 调用成员变量的特点:编译看左边,运行也看左边

编译看左边:编译时检查 “父类类型” 是否包含该成员变量,若没有则编译报错;运行看左边:运行时实际访问的是 “父类类型” 中定义的成员变量,与子类无关。

原因:成员变量属于 “对象的静态属性”,不参与多态,其访问权限在编译时就已确定。

示例:

class Father {

int num = 10; // 父类成员变量

}

class Son extends Father {

int num = 20; // 子类成员变量(隐藏父类变量)

}

public class PolymVarDemo {

public static void main(String[] args) {

// 多态引用:父类引用指向子类对象

Father father = new Son();

// 访问成员变量:编译看左边(Father有num),运行也看左边(Father的num=10)

System.out.println(father.num); // 输出:10(而非子类的20)

}

}

2. 调用成员方法的特点:编译看左边,运行看右边

编译看左边:编译时检查 “父类类型” 是否包含该方法(或其重载形式),若没有则编译报错;运行看右边:运行时实际执行的是 “子类对象” 中重写后的方法,而非父类的原方法。

原因:成员方法属于 “对象的动态行为”,多态的核心就是通过重写实现方法行为的动态绑定(运行时确定具体执行哪个类的方法)。

示例:

class Father {

public void show() { // 父类方法

System.out.println("父类的show方法");

}

}

class Son extends Father {

@Override

public void show() { // 子类重写父类方法

System.out.println("子类的show方法");

}

}

public class PolymMethodDemo {

public static void main(String[] args) {

// 多态引用:父类引用指向子类对象

Father father = new Son();

// 调用成员方法:编译看左边(Father有show()),运行看右边(Son重写的show())

father.show(); // 输出:子类的show方法

}

}

关键对比总结

成员类型编译时检查对象运行时执行对象核心原因成员变量父类(左边)父类(左边)不支持多态,静态绑定成员方法父类(左边)子类(右边)支持多态,动态绑定(重写)

三、多态的优势和弊端

多态是 Java 代码设计的核心技巧,但其特性也带来了明显的优势和局限性。

1. 多态的优势(为什么必须掌握多态)

(1)提高代码的扩展性

通过父类引用接收所有子类对象,新增子类时无需修改原有代码(符合 “开闭原则”:对扩展开放,对修改关闭)。

示例:扩展新子类无需修改调用逻辑

// 原有代码:接收Animal类型的方法

public class AnimalTool {

public static void letItMove(Animal animal) {

animal.move(); // 多态调用,无需关心具体子类

}

}

// 新增子类:无需修改AnimalTool

class Fish extends Animal {

@Override

public void move() {

System.out.println("鱼在游泳");

}

}

// 测试:直接使用新子类

public class ExtendDemo {

public static void main(String[] args) {

AnimalTool.letItMove(new Fish()); // 输出:鱼在游泳(原有代码未修改)

}

}

(2)提高代码的复用性

通过统一的父类接口编写通用逻辑,可复用在所有子类对象上(如工具类、框架代码)。

(3)简化代码逻辑

调用者只需关注父类定义的接口,无需了解每个子类的具体实现,降低代码耦合度。

2. 多态的弊端(为什么需要类型强转)

多态的核心限制是:父类引用只能访问父类中定义的成员,无法直接调用子类特有的方法。

示例:多态引用无法调用子类特有方法

class Animal {

public void move() { ... }

}

class Dog extends Animal {

@Override

public void move() { ... }

// 子类特有方法:父类中没有定义

public void bark() {

System.out.println("狗在叫:汪汪汪");

}

}

public class PolymDisadvantage {

public static void main(String[] args) {

Animal animal = new Dog(); // 多态引用

animal.move(); // 正常:父类有move()方法

// animal.bark(); // 编译报错:Animal类中没有bark()方法

// 原因:编译时检查父类,父类无bark(),即使子类有也无法直接调用

}

}

四、多态弊端的解决方法:类型强转

当需要调用子类特有方法时,需将 “父类引用” 强制转换为 “子类类型”,即类型强转。

1. 类型强转的语法

// 格式:子类类型 变量名 = (子类类型) 父类引用;

Dog dog = (Dog) animal; // 将Animal类型的animal强转为Dog类型

示例:通过强转调用子类特有方法

public class CastDemo {

public static void main(String[] args) {

Animal animal = new Dog(); // 多态引用

// 强转:将父类引用转为子类类型

Dog dog = (Dog) animal;

dog.bark(); // 调用子类特有方法,输出:狗在叫:汪汪汪

}

}

2. 强转的风险:ClassCastException

若父类引用指向的实际对象类型与强转的目标类型不匹配,会抛出ClassCastException(类型转换异常)。

示例:错误强转导致异常

public class CastErrorDemo {

public static void main(String[] args) {

Animal animal = new Bird(); // 实际是Bird对象

// 错误强转:将Bird对象转为Dog类型

Dog dog = (Dog) animal; // 运行时抛出ClassCastException

}

}

3. 安全强转:先判断后转换(instanceof 关键字)

为避免ClassCastException,强转前需用instanceof关键字判断 “父类引用指向的实际对象类型” 是否与目标类型匹配。

instanceof 的语法

// 格式:父类引用 instanceof 目标类型 → 返回boolean

if (animal instanceof Dog) {

// 若为true,说明实际是Dog对象,可安全强转

}

示例:安全的类型强转

public class SafeCastDemo {

public static void main(String[] args) {

Animal animal = new Dog(); // 实际是Dog对象

// 先判断类型,再强转

if (animal instanceof Dog) {

Dog dog = (Dog) animal;

dog.bark(); // 安全调用,输出:狗在叫:汪汪汪

} else if (animal instanceof Bird) {

Bird bird = (Bird) animal;

// 调用Bird的特有方法

}

}

}

instanceof 的核心作用

检测 “父类引用指向的实际对象” 是否是 “目标类型” 或其子孙类的实例;是多态场景下安全转换类型的 “前置校验工具”,几乎所有强转都需要配合instanceof使用。

五、多态的典型应用场景

参数统一化:方法参数定义为父类类型,可接收所有子类对象(如public void feed(Animal animal));返回值统一化:方法返回父类类型,可返回任意子类对象(如public Animal createAnimal()返回Dog或Bird);集合存储多类型对象:用父类作为集合元素类型,存储不同子类对象(如List list = new ArrayList<>(); list.add(new Dog()); list.add(new Bird()));框架设计核心:所有 Java 框架(如 Spring、MyBatis)都基于多态实现 “接口与实现分离”(如List接口与ArrayList、LinkedList实现类)。

六、多态高频面试题整理

什么是多态?实现多态的三个前提是什么? 答:多态是同一行为在不同对象上的不同表现;前提是:存在继承关系、子类重写父类方法、父类引用指向子类对象。

多态中,成员变量和成员方法的访问规则有何不同? 答:成员变量 “编译看左边,运行看左边”(不支持多态);成员方法 “编译看左边,运行看右边”(支持多态,依赖重写)。

为什么多态引用不能直接调用子类特有方法?如何解决? 答:因为编译时检查父类是否有该方法,父类无定义则编译报错;解决方法是通过类型强转((子类类型)父类引用),强转前需用instanceof判断类型。

instanceof关键字的作用是什么?为什么必须在强转前使用? 答:instanceof用于判断父类引用指向的实际对象是否为目标类型的实例;避免强转时出现ClassCastException,确保类型转换安全。

多态的优势和弊端分别是什么? 答:优势是提高代码扩展性、复用性,简化逻辑;弊端是父类引用无法直接调用子类特有方法,需通过强转解决。

重载和重写的区别?它们与多态的关系? 答:重载是同一类中同名不同参数的方法(编译时多态);重写是子类覆盖父类的方法(运行时多态)。重写是多态的核心实现,重载不直接参与多态但可丰富接口。

以下代码的运行结果是什么?为什么?

class A {

public void show() { System.out.println("A"); }

}

class B extends A {

@Override

public void show() { System.out.println("B"); }

}

public class Test {

public static void main(String[] args) {

A a = new B();

a.show(); // 输出B:多态调用子类重写的方法

System.out.println(a instanceof B); // 输出true:a实际是B对象

}

}

七、总结

多态是 Java 面向对象编程的灵魂,其核心是 “父类引用指向子类对象,方法调用动态绑定到子类实现”。掌握多态的成员访问规则(变量看左边,方法看右边)、优势(扩展性、复用性)、弊端(无法直接调用子类特有方法)及解决方案(instanceof+ 强转),是理解 Java 框架设计、写出灵活可扩展代码的基础,也是面试中考察 Java 基础能力的核心考点。

如果我的内容对你有帮助,请点赞,评论,收藏。接下来我将继续更新相关内容!

相关推荐

高级复利计算器
365永久激活怎么做到的

高级复利计算器

📅 09-12 👁️ 3616
如何在QQ音乐复制歌词
世界杯365体育

如何在QQ音乐复制歌词

📅 07-05 👁️ 2696
“终于懂了“系列:Android性能优化—FPS提升实战
365bet不能注册

“终于懂了“系列:Android性能优化—FPS提升实战

📅 08-13 👁️ 2683
Word文档的怎么翻页的 翻页的操作方法【详解】
365bet不能注册

Word文档的怎么翻页的 翻页的操作方法【详解】

📅 07-19 👁️ 7755
3P菜鳥請注意!第一次玩3P前妳該注意5件事!
世界杯365体育

3P菜鳥請注意!第一次玩3P前妳該注意5件事!

📅 07-21 👁️ 352
舞台灯光功能、设备、种类介绍
世界杯365体育

舞台灯光功能、设备、种类介绍

📅 07-20 👁️ 6692
电脑鼠标卡顿是什么原因?Win11鼠标卡顿的解决方法详解
韩国足球队世界杯历史战绩(世界杯历史战绩、成就与困境)
世界杯卫冕冠军“魔咒”究竟是什么 德国会小组赛出局吗