小熊奶糖(BearCandy)
小熊奶糖(BearCandy)
发布于 2025-08-02 / 5 阅读
0
0

Java多态性

Java多态性

多态性的基本概念

多态性是面向对象编程的三大特性之一(封装、继承、多态),指同一个行为具有多个不同表现形式或形态的能力。

方法的多态性

规则:编译看左边,运行看右边

  1. 编译时:检查左边(父类/接口)是否有该方法

    • 如果左边类中没有该方法,编译报错
  2. 运行时:执行右边(实际子类)的方法实现

    • 如果子类重写了该方法,执行子类的方法
    • 如果子类没有重写,执行父类的方法

示例代码

class Animal {
    public void eat() {
        System.out.println("动物吃东西");
    }
}

class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
  
    public void catchMouse() {
        System.out.println("猫抓老鼠");
    }
}

public class Test {
    public static void main(String[] args) {
        Animal a = new Cat();  // 向上转型
        a.eat();  // 输出"猫吃鱼" - 运行看右边(Cat)
        // a.catchMouse();  // 编译错误,编译看左边(Animal)没有此方法
    }
}

变量的多态性

规则:编译看左边,运行也看左边

  1. 编译时:检查左边(父类/接口)是否有该变量
  2. 运行时:访问左边(父类/接口)的变量值

示例代码

class Father {
    int x = 10;
}

class Son extends Father {
    int x = 20;
}

public class Test {
    public static void main(String[] args) {
        Father f = new Son();
        System.out.println(f.x);  // 输出10 - 变量编译和运行都看左边
    }
}

总结表格

元素类型 编译时检查 运行时行为
方法 看左边(父类)是否有该方法 看右边(子类)的实际实现
变量 看左边(父类)是否有该变量 看左边(父类)的变量值

注意事项

  1. 多态性只适用于实例方法,不适用于静态方法(静态方法编译和运行都看左边)
  2. 多态性不适用于成员变量(编译和运行都看左边)
  3. 多态性的实现依赖于方法重写(Override)
  4. 通过父类引用调用子类特有方法需要向下转型(需先进行instanceof检查)

Java继承与方法调用规则总结

一、问题分析

原代码问题:

Animal animal = new Dog();
animal.printDog(); // 编译错误!

错误原因:

  1. 编译时类型检查:Java编译器根据引用类型(Animal)检查方法是否存在
  2. 父类引用限制Animal类型不知道 Dog类特有的方法

二、方法类型与调用规则

1. 静态方法 (Static Methods)

class Animal {
    static void print() {
        System.out.println("Animal static");
    }
}

class Dog extends Animal {
    static void print() {
        System.out.println("Dog static");
    }
}

// 调用规则:
Animal.print();        // "Animal static" - 编译时绑定
Dog.print();           // "Dog static" - 编译时绑定

Animal animal = new Dog();
animal.print();        // "Animal static" - 看引用类型!

特点

  • 属于类,不属于对象
  • 不参与多态,编译时绑定
  • 不能被重写(Override),只能隐藏

2. 实例方法 (Instance Methods)

class Animal {
    void print() {
        System.out.println("Animal instance");
    }
}

class Dog extends Animal {
    @Override
    void print() {
        System.out.println("Dog instance");
    }
}

// 调用规则:
Animal animal = new Dog();
animal.print();        // "Dog instance" - 运行时多态

特点

  • 属于对象,参与多态
  • 运行时动态绑定
  • 可以重写(Override)

三、引用类型与对象类型

规则对比表:

引用类型 对象实际类型 可调用方法 方法绑定
Animal Animal Animal类中的方法 静态方法:编译时
实例方法:运行时
Animal Dog Animal类中声明的方法 静态方法:看Animal
实例方法:看Dog
Dog Dog Dog类中的所有方法 正常多态

四、解决方案

方案1:使用多态(推荐)

// 在父类中定义通用方法
class Animal {
    void print() {
        System.out.println("Animal");
    }
}

class Dog extends Animal {
    @Override
    void print() {
        System.out.println("Dog");
    }
}

// 使用:
Animal animal = new Dog();
animal.print(); // "Dog" - 多态生效

方案2:类型检查与转换

Animal animal = new Dog();

// 安全的方式:
if (animal instanceof Dog) {
    Dog dog = (Dog) animal;  // 向下转型
    dog.printDog();          // 调用子类特有方法
}

// 简洁方式(Java 16+):
if (animal instanceof Dog dog) {
    dog.printDog();          // 模式匹配
}

方案3:重新设计类结构

// 如果子类需要有特殊行为,考虑在父类中定义抽象方法
abstract class Animal {
    abstract void print();
}

class Dog extends Animal {
    @Override
    void print() {
        System.out.println("Dog");
    }
}

五、重要原则

  1. 编译看左边,运行看右边(实例方法)

    • 编译期:检查引用类型是否有该方法
    • 运行期:执行实际对象类型的方法
  2. 静态方法没有多态

    • 永远执行引用类型所属类的方法
  3. 向下转型需要显式检查

    • 使用 instanceof确保类型安全
    • 避免 ClassCastException
  4. 设计原则

    • 优先使用多态而非类型判断
    • 子类应该能够替换父类(里氏替换原则)

六、记忆口诀

父类引用指向子类对象,
实例方法看右边(对象类型),
静态方法看左边(引用类型),
特有方法要转型。


评论