首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Java解剖多态

Java解剖多态

作者头像
Han.miracle
发布2025-12-22 14:01:08
发布2025-12-22 14:01:08
2530
举报

多态的认识与使用技巧

多态的认识

在面向对象编程(OOP)中,多态(Polymorphism) 是三大核心特性之一(另外两个是封装和继承),其本质是 “同一行为在不同对象上表现出不同的实现”—— 简单来说,就是 “同一件事,不同对象做起来有不同的方式”。

多态的核心价值在于降低代码耦合度、提高扩展性:调用者无需关心对象的具体类型,只需调用统一的接口,就能触发对应对象的具体实现,后续新增对象时无需修改原有调用逻辑。 一、多态的核心前提 多态并非孤立存在,它需要依赖两个基础条件才能实现,缺一不可:

继承(或实现接口):存在 “父类与子类” 的层级关系(或 “接口与实现类” 的实现关系),子类继承父类的属性和方法,或实现接口定义的抽象方法。 方法重写(Override):子类对父类的 “同名、同参数列表、同返回值(或兼容返回值)” 的方法进行重新实现,覆盖父类的原有逻辑。

多态的实现条件 1.必须在继承的体系下 2.子类必须要对父类中的方法进行重写 3.通过父类的引用调用进行重写 多态的体现:咋代码运行时,当传递不同类的对象时,会调用相应类的方法。

代码语言:javascript
复制
// 1. 继承体系 - 父类
class Shape {
    // 父类中的方法,将被子类重写
    public void draw() {
        System.out.println("绘制图形");
    }
}

// 子类1
class Circle extends Shape {
    // 2. 子类重写父类方法
    @Override
    public void draw() {
        System.out.println("绘制圆形");
    }
}

// 子类2
class Rectangle extends Shape {
    // 2. 子类重写父类方法
    @Override
    public void draw() {
        System.out.println("绘制矩形");
    }
}

// 子类3
class Triangle extends Shape {
    // 2. 子类重写父类方法
    @Override
    public void draw() {
        System.out.println("绘制三角形");
    }
}

public class PolymorphismExample {
    // 3. 通过父类引用调用重写方法
    public static void drawShape(Shape shape) {
        shape.draw(); // 调用的是实际对象的draw()方法
    }

    public static void main(String[] args) {
        // 多态的体现:传递不同类的对象,调用相应类的方法
        drawShape(new Circle());      // 输出:绘制圆形
        drawShape(new Rectangle());   // 输出:绘制矩形
        drawShape(new Triangle());    // 输出:绘制三角形
    }
}

重写:

重写(Override)也称为覆盖,指的是在继承关系中,子类对父类中非静态、非 private 修饰、非 final 修饰、非构造方法的实现逻辑进行重新编写。其核心特点是 “外壳不变,核心重写”—— 方法的名称、参数列表等结构保持一致,但具体实现细节由子类根据自身需求重新定义。

重写的优势在于:子类可以基于父类的方法框架,定制符合自身特性的行为,既保留了父类的接口规范,又能实现子类的个性化逻辑。 【方法重写的规则】 方法原型一致性 1.子类重写父类方法时,必须保证返回值类型、方法名、参数列表完全一致(参数的类型、顺序、个数均需相同),这是构成重写的基础。 2.返回值类型的特殊情况,被重写的方法返回值类型可以不同,但必须满足 “父子关系”(即子类方法的返回值类型是父类方法返回值类型的子类)。 3.访问权限限制:子类重写的方法,访问权限不能低于父类中被重写方法的权限。若父类方法为public,子类重写时只能是public(不能是protected或private);若父类方法为protected,子类重写时可以是protected或public。 4.不可重写的方法:父类中以下类型的方法不能被重写: static修饰的静态方法(属于类级别的方法,不依赖对象实例); private修饰的私有方法(子类无法访问父类的私有方法); final修饰的最终方法(被final标记的方法禁止子类重写); 构造方法(构造方法是创建对象的特殊方法,子类有自己的构造方法,不存在重写概念)。 5.@Override 注解 重写方法时,建议显式添加@Override注解。该注解的作用是: 告诉编译器 “此方法是重写父类的方法”,便于编译器进行合法性校验(例如方法名拼写错误、参数列表不一致等问题会直接报错); 提高代码可读性,让其他开发者明确知道这是一个重写方法。

在这里插入图片描述
在这里插入图片描述

二、多态的两种常见形式 多态在代码中主要通过 “编译时多态” 和 “运行时多态” 体现,其中运行时多态是面向对象多态的核心。

在这里插入图片描述
在这里插入图片描述
  1. 编译时多态(方法重载) 指在同一个类中,允许存在多个 “方法名相同但参数列表不同” 的方法(参数个数、类型、顺序不同均可),编译器会根据调用时传入的参数自动匹配对应的方法。
代码语言:javascript
复制
public class Calculator {
    // 方法1:两个int相加
    public int add(int a, int b) {
        return a + b;
    }
    // 方法2:三个int相加(参数个数不同)
    public int add(int a, int b, int c) {
        return a + b + c;
    }
    // 方法3:两个double相加(参数类型不同)
    public double add(double a, double b) {
        return a + b;
    }

    public static void main(String[] args) {
        Calculator calc = new Calculator();
        System.out.println(calc.add(1, 2));        // 调用方法1,输出3
        System.out.println(calc.add(1, 2, 3));     // 调用方法2,输出6
        System.out.println(calc.add(1.5, 2.5));    // 调用方法3,输出4.0
    }
}

关键:编译时已确定调用哪个方法,本质是 “同名方法的差异化匹配”。

  1. 运行时多态(方法重写)

这是面向对象多态的核心形式:父类引用可以指向子类对象,调用方法时,程序会根据 “对象的实际类型”(而非引用类型)执行子类重写后的方法。

代码语言:javascript
复制
// 1. 父类:定义统一接口
class Animal {
    // 父类的方法(可被重写)
    public void makeSound() {
        System.out.println("动物发出声音");
    }
}

// 2. 子类1:重写父类方法
class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("小狗汪汪叫");
    }
}

// 3. 子类2:重写父类方法
class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("小猫喵喵叫");
    }
}

public class PolymorphismDemo {
    public static void main(String[] args) {
        // 父类引用指向子类对象(多态的关键语法)
        Animal animal1 = new Dog();   // 引用类型是Animal,实际对象是Dog
        Animal animal2 = new Cat();   // 引用类型是Animal,实际对象是Cat

        // 调用方法:运行时根据实际对象类型执行对应重写方法
        animal1.makeSound();  // 输出“小狗汪汪叫”(执行Dog的方法)
        animal2.makeSound();  // 输出“小猫喵喵叫”(执行Cat的方法)
    }
}

关键:编译时无法确定调用哪个方法(animal1的引用类型是Animal,编译时只知道它有makeSound方法),运行时才根据 “实际对象是Dog还是Cat” 执行对应逻辑 —— 这就是 “晚绑定”。

向上转型

  1. 定义 向上转型指的是将子类对象的引用赋值给父类类型的变量,即 “子类对象→父类引用”。这是一种自动转换,不需要显式声明。
  2. 核心特点 语法:父类类型 变量名 = new 子类类型(); 本质:父类引用指向了子类对象(引用类型变了,但实际对象还是子类) 访问限制:通过父类引用只能访问父类中定义的属性和方法,无法直接访问子类特有的属性和方法 多态基础:向上转型后,调用方法时会执行子类重写的实现(动态绑定)
代码语言:javascript
复制
class Animal {
    public void eat() {
        System.out.println("动物吃东西");
    }
}

class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }
    
    // 子类特有方法
    public void bark() {
        System.out.println("狗汪汪叫");
    }
}

public class CastDemo {
    public static void main(String[] args) {
        // 向上转型:Dog对象→Animal引用(自动转换)
        Animal animal = new Dog();
        
        // 正确:调用的是子类重写的方法(动态绑定)
        animal.eat();  // 输出:狗吃骨头
        
        // 错误:父类引用无法访问子类特有方法
        // animal.bark();  // 编译报错
    }
}

向下转型

  1. 定义 向下转型指的是将父类类型的引用转换为子类类型的变量,即 “父类引用→子类引用”。这是一种强制转换,必须显式声明(使用(子类类型))。
  2. 核心前提 向下转型必须在向上转型的基础上进行(即父类引用原本指向的就是该子类对象),否则会抛出ClassCastException(类型转换异常)。
  3. 核心特点 语法:子类类型 变量名 = (子类类型) 父类引用; 作用:将父类引用 “还原” 为子类引用,从而可以访问子类特有的属性和方法 风险:若转型的目标类型与实际对象类型不匹配,运行时会报错
代码语言:javascript
复制
public class CastDemo {
    public static void main(String[] args) {
        // 1. 先向上转型:Dog对象→Animal引用
        Animal animal = new Dog();
        
        // 2. 向下转型:Animal引用→Dog引用(强制转换)
        Dog dog = (Dog) animal;
        
        // 正确:可以访问子类特有方法
        dog.bark();  // 输出:狗汪汪叫
        
        // 错误示例:父类引用指向的是Dog对象,却转为Cat类型
        Animal animal2 = new Dog();
        // Cat cat = (Cat) animal2;  // 运行时抛出ClassCastException
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-12-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 多态的认识与使用技巧
  • 重写:
  • 向上转型
  • 向下转型
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档