Polymorphism(多态)

Polymorphism(多态)

1. 多态的优点

应用的两个条件:①父类的引用指向子类对象 ②:子类重写父类的方法

1.静态绑定(Static Binding)

  • 引用变量绑定运行时不可变对象,方法调用与定义的绑定在编译期完成。即在编译阶段就知道调用的具体函数
  • 英文:When a reference variable is bound to an unchangeable object at runtime, or method invocation binding is done at compile time.

2.动态绑定 /延迟绑定(Dynamic Binding / Late Binding)

  • 绑定在运行时可变,如多态引用场景,绑定决策在执行阶段完成。即只有在执行阶段才能知道调用的具体函数
  • 英文:Binding changeable at runtime (e.g., polymorphic references, binding decision during execution).

3.多态(Polymorphism)

  • 面向对象编程基本原则,指同一事物具多种形态。

  • 英文:Fundamental OOP principle; means something with multiple forms.

  • 多态引用(Polymorphic Reference)

    • 变量可在不同时间指向不同类型对象。
    • 英文:A variable referring to different object types at different times.
    • Java 创建方式:通过 inheritance(继承)或 interfaces(接口)。

4.多态作用

  • 支持编写含 late binding references(晚绑定引用)的程序。
  • 英文:Enables writing programs with late binding references in OOP.

5.继承与对象引用

  • 继承体系中的引用规则

    • 在继承层级中,若引用变量声明为层级树中的父类类型,该引用可指向层级内任意类的实例。(父类的引用指向子类的对象)
    • 英文:In inheritance hierarchy, a reference (declared as parent class type) can point to instances of any class in the hierarchy.
  • Object 类的引用特性

    • Java 中所有类隐式或显式继承自 Object 类,因此 Object 类型的引用变量可指向任意类实例。
    • 英文:All Java classes are subclasses of Object. Thus, an Object-type reference variable can refer to any class instance.
  • 代码示例说明

    • 示例:

      Account account;  
      account = new CCBAccount(); // This is a valid assignment  
      account = new ICBCAccount();  
      account.transferTo();  
      
    • 解释:声明为父类(Account)的引用,可动态指向子类(CCBAccountICBCAccount)实例,体现多态引用在继承体系中的灵活应用。

2. 多态实践的三个方法:
1. 方法重载(Method Overloading)
  • 核心定义:
    • 属于编译时多态(compile-time polymorphism),方法名相同,但形式参数列表(参数数量、类型、顺序)不同。
    • 英文:Overloaded methods (compile-time polymorphism) share the same name but have different formal argument lists.
  • 返回类型规则:
    • 方法的返回类型可以相同,也可以不同,非重载的判定条件。=
    • 英文:They may or may not have the same return type.
  • 多态中的角色:
    • 是 Java 中多态的三种实践形式之一(另外两种为通过继承的方法重写、通过接口的方法重写)。
    • 英文:In Java, method overloading is one of the three distinct forms of polymorphism manifestation.

注意:
在这里插入图片描述

在 Java 中,函数参数相同但返回类型不同,不属于方法重载,原因如下:

  • 重载的核心判定条件:方法重载要求方法名相同,且 参数列表(参数类型、数量、顺序)必须不同。编译器通过参数列表区分重载方法,而非返回类型。
  • 编译逻辑限制:若仅返回类型不同,参数相同,编译器无法确定调用哪个方法(例如调用时无法通过返回值约束调用行为),会直接报错 “duplicate method”,因此这种情况不满足重载的定义。

代码示例

public class Overloading {
    public int Caculate(int a, int b) {
        return a + b;
    }
    public double Caculate(double a, double b) {
        return a + b;
    }
    public int Caculate(int a, int b, int c) {
        return a + b + c;
    }

    public static void main(String[] args) {
        Overloading o = new Overloading();
        System.out.println(o.Caculate(2, 3));
        System.out.println(o.Caculate(3.56, 4.56));
        System.out.println(o.Caculate(3,4,5));
    }
}
2. 方法重写/覆盖(Override)
  • 有效重写条件:
    • 参数类型、顺序完全相同,返回类型一致,且访问权限不低于原方法(identical argument types/order, return type, not less accessible)。
    • 不能抛出原方法未声明的受检异常(must not throw undeclared checked exceptions)。
  • 执行逻辑:决定调用哪个方法版本,基于对象的实际类型,而非引用变量的类型(based on actual object type, not reference variable type)。
  • final修饰的方法不可以被覆盖
  • 不允许缩小父类的放回类型
@Override   覆盖父类Account中的同名方法(withdraw)
    public void withdraw(double amount) {
        if(getBalance()<amount) {
            System.out.println("Insufficient funds");
            System.out.println("You have not enough money to withdraw");

        }
        else {
            super.withdraw(amount);
        }
    }
3.接口(interface)

会单独介绍这里不做讲解

3.引用数据类型转换
(1)、向上转换(Upcasting)
  • 定义:将子类对象转换为父类类型,属于自动类型转换,安全且无需额外操作。
  • 核心作用:利用多态特性,统一处理不同子类对象,调用父类定义的方法(实际执行子类重写后的逻辑)。
  • 代码示例(垃圾分类场景)
public class RecyclableRubbish extends Rubbish { // 改为静态内部类
    @Override
    public void Dispose() {
        System.out.println("RecyclableRubbish");
    }
}
public  class Rubbish { // 改为静态内部类
    public void Dispose() {
        System.out.println("Rubbish");
    }
}
public class Main {
    public static void main(String[] args) {
        RecyclableRubbish R1 = new RecyclableRubbish();
        Rubbish R2 = R1;
        R2.Dispose();

    }
}
(2)、向下转换(Downcasting)
  • 定义:将父类对象转换为子类类型,属于强制类型转换,需通过 instanceof 预判,否则可能引发 ClassCastException 异常。
  • 核心作用:当确认父类引用实际指向子类对象时,转换后可访问子类特有的属性或方法。
  • 代码示例(垃圾分类场景)
public class RecyclableRubbish extends Rubbish { // 改为静态内部类
    @Override
    public void Dispose() {
        System.out.println("RecyclableRubbish");
    }
    public void RecyclableMethod(){
        System.out.println("With green method");
    }
}
public class Main {
    public static void main(String[] args) {
        RecyclableRubbish R1 = new RecyclableRubbish();
        Rubbish R2 = R1;
        R1.RecyclableMethod();
        R2.Dispose();
//       R2.RecyclableMethod();父类无法使用子类特有的方法,需要类型转化
        if(R2 instanceof RecyclableRubbish){
            RecyclableRubbish R3=(RecyclableRubbish) R2;
            R3.RecyclableMethod();
        }
        else {
            System.out.println("error!");
        }



    }
}
(3)总结
  • 向上转换:自动、安全,用于多态场景,统一调用父类定义的方法。
  • 向下转换:强制转换,需 instanceof 预判,用于访问子类特有功能。通过合理运用两种转换,可在面向对象编程中灵活处理继承体系下的对象操作,实现代码的扩展性与复用性。
4. 多态中变量与方法的调用:
(1). 非静态变量调用

在多态情况下,非静态变量的调用遵循 “编译看左边,运行看左边” 原则。即编译时看引用变量所属类(父类 )中是否有该变量定义;运行时,实际使用的也是父类中定义的该变量值 。
示例代码:

class Parent {
    String name = "parent";
}
class Child extends Parent {
    String name = "child";
}
public class Main {
    public static void main(String[] args) {
        Parent p = new Child();
        System.out.println(p.name); 
    }
}

上述代码中,Parent p = new Child(); ,编译时 pParent 类型,检查 Parent 类有 name 变量可通过编译;运行时,输出的是 Parent 类中 name 变量的值 parent

(2). 非静态方法调用

非静态方法调用遵循 “编译看左边,运行看右边” 原则。编译时,看引用变量所属类(父类 )是否有要调用的方法;运行时,看实际创建对象所属类(子类 )中的方法,若子类重写了该方法,就调用子类重写后的方法。
示例代码:

class Animal {
    public void speak() {
        System.out.println("Animal makes sound");
    }
}
class Dog extends Animal {
    @Override
    public void speak() {
        System.out.println("Dog barks");
    }
}
public class Main {
    public static void main(String[] args) {
        Animal a = new Dog();
        a.speak(); 
    }
}

这里 Animal a = new Dog(); ,编译时 aAnimal 类型,Animal 类有 speak 方法可通过编译;运行时,实际创建的是 Dog 对象,Dog 类重写了 speak 方法,所以输出 Dog barks

(3). 静态变量调用

静态变量属于类本身,在多态中,无论编译还是运行,都看引用变量所属类(父类 ) 。
示例代码:

class Animal {
    static String name="Animal";
    public void speak(){
        System.out.println("I'm an animal");
    }
}
class Dog extends Animal {
    static String name="Dog";
    @Override
    public void speak(){
        System.out.println("I'm a dog");
    }
}
public class Main {
    public static void main(String[] args) {
        Animal a = new Dog();
        System.out.println(a.name);
        System.out.println(Animal.name);//推荐使用类名.属性来调用静态属性,Animal
        System.out.println(Dog.name);//推荐使用类名.属性来调用静态属性,Dog
    }
}

StaticClass sc = new SubStaticClass(); ,编译和运行时,sc 作为 StaticClass 类型引用,使用的都是 StaticClass 类中的 staticVar ,输出 static in parent

(4). 静态方法调用

静态方法同样属于类,多态中,编译和运行都依据引用变量所属类(父类 ) 。
示例代码:

class Animal {
    static String name="Animal";
    public static void speak(){
        System.out.println("I'm an animal");
    }
}
class Dog extends Animal {
    static String name="Dog";

    public static void speak(){
        System.out.println("I'm a dog");
    }
}
public class Main {
    public static void main(String[] args) {
        Animal animal = new Dog();
        animal.speak();
        Animal.speak();
        Dog.speak();
    }
}

MathUtils mu = new AdvancedMathUtils(); ,编译和运行时,以 MathUtils 类为准,调用的是 MathUtils 类中的 add 方法,输出 3

例题:

在这里插入图片描述

在这里插入图片描述

答案

(1) B
(2) D
(3) E
(4) D
(5) E
(6) F

解析
  • 方法重载:在BaseClassA中,多个methodA方法参数列表不同,构成方法重载。方法调用时,根据传入参数的数量、类型和顺序来匹配对应的方法。
  • 方法重写DevrivedClassB中的methodA(int a)重写了BaseClassA中的methodA(int a) ,当父类引用指向子类对象调用该方法时,执行子类重写后的逻辑。
  1. (1) objA.methodA(12);objA此时是BaseClassA对象,传入int类型参数12 ,匹配BaseClassApublic void methodA(int a) ,即 B 方法。
  2. (2) objA.methodA(21.3);objABaseClassA对象,传入double类型参数21.3 ,匹配BaseClassApublic void methodA(double a) ,即 D 方法。
  3. (3) objA.methodA(90);objA此时指向DevrivedClassB对象,传入int类型参数90DevrivedClassB重写了BaseClassAmethodA(int a) ,所以执行子类重写后的方法 E。
  4. (4) objA.methodA(65.5);objA指向DevrivedClassB对象 ,传入double类型参数65.5DevrivedClassB未重写BaseClassAmethodA(double a) ,所以调用BaseClassA中的public void methodA(double a) ,即 D 方法。
  5. (5) objB.methodA(21);objBDevrivedClassB对象 ,传入int类型参数21 ,调用DevrivedClassB中重写的public void methodA(int a) ,即 E 方法。
  6. (6) objB.methodA(11.1, 78.3);objBDevrivedClassB对象 ,传入两个double类型参数,调用DevrivedClassB中的public void methodA(double a, double b) ,即 F 方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值