多态
对象多态:将方法的形参定义为父类类型,这个方法可以接收该父类的任意子类对象;形参既能接受狗,也能接收猫,对象多态; 行为多态:同一个方法具有不同的表现形式或形态的能力;同一个 eat 方法,有不同的表现,即行为多态;

多态前提
- 有继承或者实现关系
- 有方法重写
- 有父类引用指向子类对象

java
package com.ruoyi.system.test;
public class PolymorphismDemo {
public static void main(String[] args) {
/**
* ## 多态前提:
* - 有继承或者实现关系
* - 有方法重写
* - 有父类引用指向子类对象
*
* 多态的成员访问特点:
*
* 成员变量:编译看左边(父类),运行看左边(父类)
* 因为是父类的引用,所以访问存在局限性,只能访问super空间中的数据
*
* 成员方法:编译看左边(父类),运行看右边(子类)
* 编译时检查方法在父类中是否存在,不存在则编译报错;存在则编译通过,但是运行时执行子类的方法
* 为什么运行看右边,因为父类中定义的方法如果是抽象方法,运行父类中的方法没有任何意义
*
* 静态成员:编译看左边(父类),运行看左边(父类)
* static 修饰的成员,推荐使用类型调用
* 即使对象调用,在字节码文件中 还是被改为类名调用 f.show() ---> 字节码文件中 --> Fu.show()
* 所以父类调方法,肯定使用父类的逻辑
* 静态方法随类,没有Override
*/
// 子类引用指向子类对象
Zi zi = new Zi();
System.out.println(zi.num); //20
zi.show(); //子类方法 show
// 父类引用指向子类对象(以多态的形式创建了对象)
Fu fu = new Zi();
System.out.println(fu.num); //10
fu.show(); //子类方法 show
// 接口类型变量,指向了实现类对象也是多态的形式
Inter inter = new InterImpl();
}
}
interface Inter {
void show();
}
class Fu {
int num = 10;
public void show() {
System.out.println("父类方法 show");
}
}
class Zi extends Fu {
int num = 20;
@Override
public void show() {
System.out.println("子类方法 show");
}
}
class InterImpl implements Inter {
@Override
public void show() {
System.out.println("show()方法被调用");
}
}多态的好处:提高代码的扩展性
- 方法的形参定义为父类类型,就可以传入该类的任意子类对象了;
java
// 定义动物父类
abstract class Animal {
public abstract void makeSound();
}
// 狗类继承动物类
class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("汪汪汪!");
}
}
// 猫类继承动物类
class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("喵喵喵!");
}
}
// 动物表演类
class AnimalShow {
// 使用父类类型作为参数,可以接收任何Animal的子类对象
public static void perform(Animal animal) {
System.out.print("动物表演节目:");
animal.makeSound(); // 调用实际对象的重写方法
}
}
// 测试类
public class PolymorphismTest {
public static void main(String[] args) {
// 可以传入Dog对象
AnimalShow.perform(new Dog()); // 输出:动物表演节目:汪汪汪!
// 也可以传入Cat对象
AnimalShow.perform(new Cat()); // 输出:动物表演节目:喵喵喵!
// 如果以后增加了新的动物子类,比如Bird,这个方法也能直接使用
// AnimalShow.perform(new Bird()); // 无需修改现有代码
}
}多态的弊端:不能调用子类特有的成员变量和成员方法;
java
// 父类
class Animal {
public void eat() {
System.out.println("动物吃饭");
}
}
// 子类,拥有父类没有的方法和属性
class Dog extends Animal {
public int age = 5; // 子类特有属性
public void eat() {
System.out.println("狗吃骨头");
}
// 子类特有方法
public void watchHouse() {
System.out.println("狗看家");
}
}
// 测试类
public class PolymorphismLimitation {
public static void main(String[] args) {
// 多态形式创建对象
Animal animal = new Dog();
// 可以调用父类中存在的方法
animal.eat(); // 正常执行
// 无法直接访问子类特有的属性
// System.out.println(animal.age); // 编译错误!父类中没有age属性
// 无法直接调用子类特有的方法
// animal.watchHouse(); // 编译错误!父类中没有watchHouse方法
}
}多态中的转型

- 需要向下转型
- ClassCaseException: 类型转换异常 原因:在强转过程中,如果目标类型和实际类型,不是同一种类型,就会出现异常 instanceof: 判断左边的变量,记录的是不是右边的类型
编译看左边,编译阶段就报错,左边的父类没有; 怎么解决弊端,多态的转型;
小的给大的,子给父,能直接赋值; 大的给小的, 需要加括号 强转;
java
// 父类
class Animal {
public void eat() {
System.out.println("动物吃饭");
}
}
// 子类,拥有特有方法
class Dog extends Animal {
public void eat() {
System.out.println("狗吃骨头");
}
// 子类特有方法
public void watchHouse() {
System.out.println("狗看家");
}
}
// 猫类
class Cat extends Animal {
public void eat() {
System.out.println("猫吃鱼");
}
}
// 测试转型
public class PolymorphismCast {
public static void main(String[] args) {
// 向上转型(自动):子类转父类
Animal animal = new Dog(); // 小的给大的,直接赋值
// 调用父类存在的方法
animal.eat(); // 输出:狗吃骨头(动态绑定)
// 向下转型(强制):父类转子类,需要强转才能调用子类特有方法
Dog dog = (Dog) animal; // 大的给小的,需要强转
dog.watchHouse(); // 现在可以调用子类特有方法了
// 使用instanceof避免ClassCastException
if (animal instanceof Dog) {
Dog dog2 = (Dog) animal;
dog2.watchHouse();
}
// 错误的转型示例
// Animal cat = new Cat();
// Dog wrongDog = (Dog) cat; // ClassCastException!猫不能转成狗
}
}多态案例:模拟订单
java
package com.ruoyi.system.order;
public interface OrderService {
/**
* 创建订单
*/
void create();
/**
* 查询订单
*/
void findOne();
/**
* 查询订单列表
*/
void findList();
/**
* 取消订单
*/
void cancel();
/**
* 订单完成
*/
void finish();
/**
* 支付订单
*/
void paid();
}java
package com.ruoyi.system.order;
public class OrderServiceImpl implements OrderService {
@Override
public void create() {
System.out.println("创建订单");
}
@Override
public void findOne() {
System.out.println("查询订单");
}
@Override
public void findList() {
System.out.println("查询订单列表");
}
@Override
public void cancel() {
System.out.println("取消订单");
}
@Override
public void finish() {
System.out.println("完成订单");
}
@Override
public void paid() {
System.out.println("支付订单");
}
}java
package com.ruoyi.system.order;
public class OverseasImpl implements OrderService {
public void check(){
System.out.println("ip地址检测");
}
@Override
public void create() {
System.out.println("海外订单--创建");
}
@Override
public void findOne() {
System.out.println("海外订单--查询");
}
@Override
public void findList() {
System.out.println("海外订单--查询列表");
}
@Override
public void cancel() {
System.out.println("海外订单--取消");
}
@Override
public void finish() {
System.out.println("海外订单--完成");
}
@Override
public void paid() {
System.out.println("海外订单--支付");
}
}java
package com.ruoyi.system.order;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入订单类型:1.普通订单 2.海外订单");
int orderType = scanner.nextInt();
OrderService orderService = null;
switch (orderType) {
case 1:
orderService = new OrderServiceImpl(); // 对象多态
break;
case 2:
orderService = new OverseasImpl();
OverseasImpl overseas = (OverseasImpl) orderService; // 强转 父强转给子;强转成自己的类型 那不就能调了
// 特有方法
overseas.check();
break;
}
// 行为多态
orderService.create();
orderService.findOne();
orderService.findList();
orderService.cancel();
orderService.finish();
orderService.paid();
}
}