学习Java38天

Java 多态 (Polymorphism)

多态是面向对象三大特性中最核心、最灵活的特性。它意味着 "同一行为,多种实现"

一、多态的基本概念

  • 定义:同一种类型的对象(或引用),在不同的情况下表现出不同的行为和状态。

  • 核心表现形式(向上转型):

    java

    复制代码
    父类类型 引用名 = new 子类对象();

    例如

    java

    复制代码
    Animal a = new Dog(); // 多态
    Animal b = new Cat(); // 多态

    这里的 Animal 是编译时类型,而 DogCat 是运行时类型。

  • 多态的前提条件(三者缺一不可)

    1. 有继承关系实现关系(接口)。

    2. 有父类(或接口)引用指向子类对象(即向上转型)。

    3. 有方法的重写(否则多态调用方法没有实际意义)。

二、多态的优势

  1. 降低耦合度,提高扩展性:方法参数或容器(如集合)使用父类类型,可以接受任何子类对象,代码通用性更强。

  2. 便于维护:当需要新增一种子类时,无需修改使用父类引用的代码。

  3. 代码简洁:统一的接口,不同的实现。

示例:体现扩展性的优势

java

复制代码
class Animal {
    public void eat() {
        System.out.println("动物吃东西");
    }
}
class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }
}
class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
}

// 饲养员类 - 核心优势体现
class Keeper {
    // 参数使用父类类型,可以接收任何Animal子类对象
    public void feedAnimal(Animal a) {
        a.eat(); // 运行时执行具体子类的eat方法
    }
}

public class Main {
    public static void main(String[] args) {
        Keeper keeper = new Keeper();
        
        Animal dog = new Dog();
        Animal cat = new Cat();
        
        keeper.feedAnimal(dog); // 输出:狗吃骨头
        keeper.feedAnimal(cat); // 输出:猫吃鱼
        
        // 未来新增一个Tiger类,Keeper类完全无需修改!
        // keeper.feedAnimal(new Tiger());
    }
}

三、多态调用成员的特点(记忆口诀)

这是理解多态行为的关键:

成员类型 编译阶段(看左边) 运行阶段(看右边) 说明
成员变量 检查父类中是否有该变量 访问父类中的该变量 编译和运行都看左边(父类)
成员方法 检查父类中是否有该方法声明 执行子类中重写后的该方法 编译看左边,运行看右边(子类)

示例

java

复制代码
class Fu {
    int num = 10;
    public void show() {
        System.out.println("Fu show");
    }
}
class Zi extends Fu {
    int num = 20;
    @Override
    public void show() {
        System.out.println("Zi show");
    }
    public void special() {
        System.out.println("Zi special");
    }
}

public class Test {
    public static void main(String[] args) {
        Fu obj = new Zi(); // 多态
        
        // 访问成员变量:看左边(Fu)
        System.out.println(obj.num); // 输出:10
        
        // 调用成员方法:编译看左边(Fu),运行看右边(Zi)
        obj.show(); // 输出:Zi show
        
        // obj.special(); // 编译错误!因为编译看左边,Fu类中没有special方法声明
    }
}

四、多态的弊端与解决方案:类型转换

弊端 :在多态的形式下(父类引用),不能调用子类特有的方法或访问子类特有的变量

解决方案 :使用 引用数据类型转换

1. 向上转型 (Upcasting)
  • 自动进行:子类类型转换为父类类型。

  • Animal a = new Dog(); // 安全,因为狗一定是动物。

2. 向下转型 (Downcasting)
  • 强制进行:父类类型转换为子类类型。

  • 语法子类类型 引用名 = (子类类型) 父类引用;

  • 目的 :为了 "还原" 对象的真实子类类型,以便调用子类特有的功能。

示例

java

复制代码
Animal a = new Dog(); // 向上转型
Dog d = (Dog) a;      // 向下转型,将a强制转换为Dog类型
d.lookHome();         // 现在可以调用Dog特有的方法了
3. 转型的风险与安全校验

如果转型的目标类型与对象的真实类型不匹配,会抛出 ClassCastException(类型转换异常)。

java

复制代码
Animal a = new Cat();
Dog d = (Dog) a; // 运行时错误!ClassCastException: Cat cannot be cast to Dog

安全转型:使用 instanceof 关键字

  • 作用 :在转型前进行判断,避免 ClassCastException

  • 语法引用变量 instanceof 数据类型

  • 结果 :返回 boolean 值。判断引用指向的对象是否属于该类型(或该类型的子类)。

示例

java

复制代码
public static void checkAnimal(Animal a) {
    a.eat(); // 所有动物都有的行为
    
    // 类型判断与安全转型
    if (a instanceof Dog) {
        Dog dog = (Dog) a;
        dog.lookHome();
    } else if (a instanceof Cat) {
        Cat cat = (Cat) a;
        cat.catchMouse();
    } else {
        System.out.println("这是其他动物");
    }
}

五、总结与最佳实践

  1. 多态的本质:通过父类/接口引用调用方法,执行时由JVM根据对象的实际类型决定调用哪个版本的方法(动态绑定)。

  2. 使用场景:当需要编写通用代码、处理一组相关对象、或设计可扩展的系统架构时。

  3. 转型原则

    • 能向上转型就向上转型(利用多态,提高代码通用性)。

    • 必须向下转型时才转(需要使用子类特有功能时)。

    • 向下转型前务必用 instanceof 判断,确保类型安全。

java 复制代码
package polymorphism02;

public class Animal {
    private int age;
    private String color;

    public Animal() {
    }

    public Animal(int age, String color) {
        this.age = age;
        this.color = color;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public void eat(String something){
        System.out.println("动物在吃东西");
    }
}
java 复制代码
package polymorphism02;

public class Cat extends Animal{
    public Cat() {
    }

    public Cat(int age, String color) {
        super(age, color);
    }

    @Override
    public void eat(String something){
        System.out.println(getAge()+"岁的"+getColor()+"颜色的猫在吃"+something);
    }

    public void catchMouse(){
        System.out.println("猫抓老鼠");
    }
}
java 复制代码
package polymorphism02;

public class Dog extends Animal{
    public Dog() {
    }

    public Dog(int age, String color) {
        super(age, color);
    }
    @Override
    public void eat(String something){
        System.out.println(getAge()+"岁的"+getColor()+"颜色的狗在吃"+something);
    }
    public void lookHome(){
        System.out.println("狗在看家");
    }
}
java 复制代码
package polymorphism02;

public class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    //饲养狗
    /*public void keepPet(Dog dog,String something){
        System.out.println("年龄为"+age+"岁的"+name+"养了一只"+dog.getColor()+"颜色的"+dog.getAge()+"岁的狗");
        dog.eat(something);
    }
    //饲养猫
    public void keepPet(Cat cat,String something){
        System.out.println("年龄为"+age+"岁的"+name+"养了一只"+cat.getColor()+"颜色的"+cat.getAge()+"岁的猫");
        cat.eat(something);
    }*/

    //一个方法能接收使用动物信息
    //方法的形参:可以写这些类的父类
    public void keepPet(Animal a ,String something){
        if (a instanceof Dog d){
            System.out.println("年龄为"+age+"岁的"+name+"养了一只"+d.getColor()+"颜色的"+d.getAge()+"岁的狗");
            d.eat(something);
        }else if (a instanceof Cat c){
            System.out.println("年龄为"+age+"岁的"+name+"养了一只"+c.getColor()+"颜色的"+c.getAge()+"岁的猫");
            c.eat(something);
        }else {
            System.out.println("没有这种动物");
        }

    }
}
java 复制代码
package polymorphism02;

public class Test {
    public static void main(String[] args) {
        //创建对象并调用
        /*Person p = new Person(30, "老王");
        Dog d = new Dog(2,"黑");
        p.keepPet(d,"骨头");

        Person p1 = new Person(26, "老李");
        Cat d1 = new Cat(3,"黄");
        p1.keepPet(d1,"🐟");
        */

        Person p = new Person(30, "老王");
        Dog d = new Dog(2,"黑");
        Cat c = new Cat(3,"黄");
        p.keepPet(d,"骨头");
        p.keepPet(c,"🐟");


    }
}
相关推荐
好奇龙猫2 小时前
【日语学习-日语知识点小记-日本語体系構造-JLPT-N2前期阶段-第一阶段(3):单词语法】
学习
儒雅永缘2 小时前
Solidworks练习39-拉伸、拉伸切
笔记·学习
来两个炸鸡腿2 小时前
【Datawhale组队学习202601】Base-NLP task01 注意力机制与Transformer
学习·自然语言处理·transformer
am心3 小时前
学习笔记-缓存&添加购物车
笔记·学习·缓存
Engineer邓祥浩3 小时前
设计模式学习(10) 23-8 装饰者模式
python·学习·设计模式
Errorbot3 小时前
F570四轴飞行器学习笔记
笔记·学习·无人机
GISer_Jing3 小时前
AI学习资源总结:免费开放,入门至深入,持续更新
人工智能·学习·设计模式·prompt·aigc
_Kayo_3 小时前
Node.JS 学习笔记7
笔记·学习·node.js
默大老板是在下4 小时前
【个人成长】我和自己的博弈:在“自我约束”中重构人生系统
笔记·学习·重构·生活