深入理解 Java 中的多态、重写与重载

目录

1. 多态(Polymorphism)

1.1 什么是多态?

1.2 多态的优势

1.3 案例中的多态

输出

2. 重写(Override)

2.1 什么是重写?

2.2 重写的规则

2.3 案例中的重写

3. 重载(Overload)

3.1 什么是重载?

3.2 重载的规则

3.3 案例中的重载

4. 案例二:多态、重写与重载的综合应用

4.1 案例代码

4.2 输出结果

4.3 详细分析

4.3.1 a1.show(b)

4.3.2 a1.show(c)

4.3.3 a1.show(d)

4.3.4 a2.show(b)

4.3.5 a2.show(c)

4.3.6 a2.show(d)

4.3.7 b.show(b)

4.3.8 b.show(c)

4.3.9 b.show(d)

5. 总结

关键点


在 Java 编程中,多态重写 和 重载 是面向对象编程的三大核心概念。它们分别用于实现方法的动态调用、子类对父类方法的扩展以及方法的多样化实现。本文将通过两个具体的案例,详细解释这三个概念的含义、区别以及实际应用。

先看案例一

// 父类
class Animal {
    public void makeSound() {
        System.out.println("Animal is making a sound");
    }
}

// 子类
class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Dog is barking");
    }
    
    public void fetch() {
        System.out.println("Dog is fetching the ball");
    }
}

public class Main {
    public static void main(String[] args) {
        // 1. 父类引用指向子类对象
        Animal myAnimal = new Dog();  // 向上转型

        // 2. 调用方法
        myAnimal.makeSound();  // 实际执行的是 Dog 类中重写的 makeSound 方法

        // 3. 无法调用子类特有的方法
        // myAnimal.fetch();  // 这行代码会报错,因为 Animal 类中没有 fetch 方法
    }
}

案例分析

多态
  • 定义:父类引用可以指向子类对象,但在调用方法时,实际执行的是子类重写的方法。

  • 示例

Animal myAnimal = new Dog();  // 向上转型
myAnimal.makeSound();         // 输出:Dog is barking

父类引用可以指向子类对象

Animal myAnimal = new Dog();  // 向上转型
  • 解释

    • Animal 是父类,Dog 是子类。

    • myAnimal 是 Animal 类型的引用,但它指向的是一个 Dog 类的对象。

    • 这种操作称为 向上转型(Upcasting),即将子类对象赋值给父类引用。

调用方法时,实际执行的是子类重写的方法

  • 代码

myAnimal.makeSound();  // 输出:Dog is barking
  • 解释

    • myAnimal 是 Animal 类型的引用,但它实际指向的是 Dog 类的对象。

    • Dog 类重写了 Animal 类中的 makeSound 方法。

    • 因此,调用 myAnimal.makeSound() 时,实际执行的是 Dog 类中重写的 makeSound 方法,而不是 Animal 类中的方法。

    • 这就是 多态 的核心:编译时看左边(引用类型),运行时看右边(实际对象类型)

多态的核心规则
  1. 编译时看左边(引用类型)

    • 编译器根据引用类型决定可以调用哪些方法。

    • 例如,myAnimal 是 Animal 类型的引用,因此只能调用 Animal 类中定义的方法。

  2. 运行时看右边(实际对象类型)

    • 运行时根据实际对象类型决定调用哪个具体的方法。

    • 例如,myAnimal 实际指向的是 Dog 类的对象,因此调用的是 Dog 类中重写的方法。

重写
  • 定义:子类重新定义父类中的方法,方法名、参数列表和返回类型必须相同。

  • 示例

@Override
public void makeSound() {
    System.out.println("Dog is barking");
}
  • 解释

    • Dog 类重写了 Animal 类中的 makeSound 方法。

    • 当通过父类引用调用 makeSound 方法时,实际执行的是 Dog 类中重写的方法。


1. 多态(Polymorphism)

1.1 什么是多态?

多态是指 父类引用可以指向子类对象,但在调用方法时,实际执行的是子类重写的方法。多态的核心规则是:

  • 编译时看左边(引用类型):编译器根据引用类型决定可以调用哪些方法。

  • 运行时看右边(实际对象类型):运行时根据实际对象类型决定调用哪个具体的方法。

1.2 多态的优势

  • 灵活性:可以在运行时动态选择方法实现。

  • 可扩展性:新增子类时,无需修改父类代码。

1.3 案例中的多态

在案例中,Animal myAnimal = new Dog(); 是一个典型的多态示例:

  • myAnimal 是 Animal 类型的引用,但它实际指向的是 Dog 类的对象。

  • 调用 myAnimal.makeSound() 时,实际执行的是 Dog 类中重写的 makeSound 方法,而不是 Animal 类中的方法。

输出

Dog is barking


2. 重写(Override)

2.1 什么是重写?

重写是指 子类重新定义父类中的方法,方法名、参数列表和返回类型必须相同。重写的目的是扩展或修改父类方法的行为。

2.2 重写的规则

  • 方法名、参数列表和返回类型必须与父类方法相同。

  • 访问修饰符不能比父类方法更严格(例如,父类方法是 public,子类方法不能是 private)。

  • 不能重写 final 或 static 方法。

2.3 案例中的重写

在案例中,Dog 类重写了 Animal 类中的 makeSound 方法:

@Override
public void makeSound() {
    System.out.println("Dog is barking");
}
  • @Override 注解表示该方法是对父类方法的重写。

  • 当通过父类引用调用 makeSound 方法时,实际执行的是 Dog 类中重写的方法。


3. 重载(Overload)

3.1 什么是重载?

重载是指 在同一个类中,方法名相同但参数列表不同。重载的目的是提供多种方法实现,方便调用。

3.2 重载的规则

  • 方法名必须相同。

  • 参数列表必须不同(参数类型、参数个数或参数顺序)。

  • 返回类型可以不同,但不能仅靠返回类型区分重载。

3.3 案例中的重载

在案例二中,A 类和 B 类中都定义了多个 show 方法,参数列表不同:

// A 类中的重载
public String show(D obj) {
    return ("A and D");
}
public String show(A obj) {
    return ("A and A");
}

// B 类中的重载
public String show(B obj) {
    return ("B and B");
}
public String show(A obj) {
    return ("B and A");
}
  • A 类中的 show(D obj) 和 show(A obj) 是重载。

  • B 类中的 show(B obj) 和 show(A obj) 是重载。


4. 案例二:多态、重写与重载的综合应用

4.1 案例代码

public class A {
    public String show(D obj) {
        return ("A and D");
    }
    public String show(A obj) {
        return ("A and A");
    } 
}

public class B extends A {
    public String show(B obj) {
        return ("B and B");
    }
    
    public String show(A obj) {
        return ("B and A");
    } 
}

public class C extends B {
}

public class D extends B {
}

public class Test {
    public static void main(String[] args) {
        A a1 = new A();
        A a2 = new B();
        B b = new B();
        C c = new C();
        D d = new D();
        
        System.out.println("1--" + a1.show(b));
        System.out.println("2--" + a1.show(c));
        System.out.println("3--" + a1.show(d));
        
        System.out.println("4--" + a2.show(b));
        System.out.println("5--" + a2.show(c));
        System.out.println("6--" + a2.show(d));
        
        System.out.println("7--" + b.show(b));
        System.out.println("8--" + b.show(c));
        System.out.println("9--" + b.show(d));      
    }
}

4.2 输出结果

1--A and A
2--A and A
3--A and D
4--B and A
5--B and A
6--A and D
7--B and B
8--B and B
9--A and D

4.3 详细分析

4.3.1 a1.show(b)
  • a1A 类的对象。

  • bB 类的对象。

  • 分析

    • A 类中没有 show(B obj) 方法,但 B 是 A 的子类,因此会调用 A 类中的 show(A obj) 方法。

    • 重载A 类中的 show(A obj) 方法。

    • 没有使用多态,因为 a1 是 A 类的对象,直接调用 A 类的方法。

  • 输出A and A

4.3.2 a1.show(c)
  • a1A 类的对象。

  • cC 类的对象。

  • 分析

    • C 是 B 的子类,B 是 A 的子类,因此会调用 A 类中的 show(A obj) 方法。

    • 重载A 类中的 show(A obj) 方法。

    • 没有使用多态,因为 a1 是 A 类的对象,直接调用 A 类的方法。

  • 输出A and A

4.3.3 a1.show(d)
  • a1A 类的对象。

  • dD 类的对象。

  • 分析

    • A 类中有 show(D obj) 方法,因此会直接调用 A 类中的 show(D obj) 方法。

    • 重载A 类中的 show(D obj) 方法。

    • 没有使用多态,因为 a1 是 A 类的对象,直接调用 A 类的方法。

  • 输出A and D

4.3.4 a2.show(b)
  • a2A 类引用,指向 B 类的对象(向上转型)。

  • bB 类的对象。

  • 分析

    • a2 是 A 类引用,只能调用 A 类中定义的方法(show(D obj) 和 show(A obj))。

    • B 类重写了 show(A obj) 方法,因此会调用 B 类中重写的 show(A obj) 方法。

    • 多态a2 是 A 类引用,但实际指向 B 类的对象,调用的是 B 类中重写的方法。

    • 重写B 类重写了 A 类中的 show(A obj) 方法。

  • 输出B and A

4.3.5 a2.show(c)
  • a2A 类引用,指向 B 类的对象(向上转型)。

  • cC 类的对象。

  • 分析

    • C 是 B 的子类,B 是 A 的子类,因此会调用 B 类中重写的 show(A obj) 方法。

    • 多态a2 是 A 类引用,但实际指向 B 类的对象,调用的是 B 类中重写的方法。

    • 重写B 类重写了 A 类中的 show(A obj) 方法。

  • 输出B and A

4.3.6 a2.show(d)
  • a2A 类引用,指向 B 类的对象(向上转型)。

  • dD 类的对象。

  • 分析

    • A 类中有 show(D obj) 方法,因此会直接调用 A 类中的 show(D obj) 方法。

    • 重载A 类中的 show(D obj) 方法。

    • 没有使用多态,因为 A 类中有匹配的方法,直接调用 A 类的方法。

  • 输出A and D

4.3.7 b.show(b)
  • bB 类的对象。

  • bB 类的对象。

  • 分析

    • B 类中有 show(B obj) 方法,因此会直接调用 B 类中的 show(B obj) 方法。

    • 重载B 类中的 show(B obj) 方法。

    • 没有使用多态,因为 b 是 B 类的对象,直接调用 B 类的方法。

  • 输出B and B

4.3.8 b.show(c)
  • bB 类的对象。

  • cC 类的对象。

  • 分析

    • C 是 B 的子类,因此会调用 B 类中的 show(B obj) 方法。

    • 重载B 类中的 show(B obj) 方法。

    • 没有使用多态,因为 b 是 B 类的对象,直接调用 B 类的方法。

  • 输出B and B

4.3.9 b.show(d)
  • bB 类的对象。

  • dD 类的对象。

  • 分析

    • B 类中没有 show(D obj) 方法,但 D 是 B 的子类,因此会调用 A 类中的 show(D obj) 方法。

    • 重载A 类中的 show(D obj) 方法。

    • 没有使用多态,因为 B 类中没有匹配的方法,直接调用 A 类的方法。

  • 输出A and D


5. 总结

特性多态重写重载
定义父类引用指向子类对象,调用子类方法子类重新定义父类方法同一个类中,方法名相同但参数列表不同
作用实现动态调用扩展或修改父类方法的行为提供多种方法实现,方便调用
调用规则编译时看左边,运行时看右边子类方法覆盖父类方法根据参数列表选择合适的方法
适用场景父类引用指向子类对象子类需要修改父类方法的行为同一个类中需要多种方法实现

关键点

  • 多态:通过父类引用指向子类对象,实现方法的动态调用。

  • 重写:子类重新定义父类方法,扩展或修改父类方法的行为。

  • 重载:在同一个类中,方法名相同但参数列表不同,提供多种方法实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值