Java初阶(多态)

文章详细介绍了多态的概念,包括方法的重写、向上转型和动态绑定。通过示例代码解释了如何在Java中实现多态,强调了方法重写时的注意事项,并对比了静态绑定与动态绑定的区别。此外,还讨论了向下转型的使用及其可能的风险,以及多态在代码设计中的优缺点。
摘要由CSDN通过智能技术生成

一、什么是多态

同一件事情作用在不同的对象中,呈现出了不同的效果,这种效果称为多态

例如:
如果我们要打印纸张,同一件事情,打印机通过设置,可以彩色打印 or 黑白打印

二、如何实现多态

2.1 条件

  • 必须在继承体系下,向上转型(是is-a的另一种表达,所有的猫、狗都是动物)
  • 子类必须要对父类中方法进行重写
  • 通过父类的引用调用重写的方法(动态绑定)
class Father{

    public void eat(){
        System.out.println("正在吃饭");
    }
}

class Son extends Father{
    public void eat(){    //方法的重写
        System.out.println("正在吃黄焖鸡米饭");
    }
}
public class Main {
    public static void main(String[] args) {
        Father son = new Son();
        son.eat();
    }
}

在这里插入图片描述

2.2 方法的重写

1.方法重写

  • 重写(override):也称为覆盖。
  • 重写是子类对父类非静态、非private修饰,非final修饰,非构造方法等的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!
  • 重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。

❤️重写原理理解

  1. 结合下面方法调用的步骤

  2. 方法的名字和参数列表称为方法的签名。例如, f(int) 和 f(String)是两个具有相同名字, 不同签名的方法。如果在子类中定义了一个与超类签名相同的方法, 那么子类中的这个方法就覆盖了超类中的这个相同签名的方法。

  3. 不过,返回类型不是签名的一部分, 因此,在覆盖方法时, 一定要保证返回类型的兼容性。 允许子类将覆盖方法的返回类型定义为原返回类型的子类型或者相同

❤️哪些情况下不能方法重写

  • 被private修饰的方法不能重写
  • 被static修饰的方法不能重写 -----------> 不依赖对象
  • 被final修饰的方法,不能被重写
  • 构造方法不能被重写(因为构造方法无法被继承)
  • 子类的访问修饰限定符一定要大于等于父类的访问修饰限定符

❤️快捷键

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

2.方法重写 VS 方法重载

方法重写方法重载
方法名一样一样
参数列表(个数、类型、顺序)可以不一样,但一定要是父子关系不一样
返回类型一样无要求

2.3 向上转型

概念:实际就是创建一个子类对象,将其当成父类对象来使用。
语法格式:父类类型 对象名 = new 子类类型()
是从小范围向大范围的转变
优点:让代码实现更简单灵活。
缺陷:不能调用到子类特有的方法

class Father{
    public void eat(){
        System.out.println("吃饭");
    }
}

class Son extends  Father{
    public void eat(){
        System.out.println("正在吃黄焖鸡米饭");
    }
}

public class Main {
    public static void main(String[] args) {
        Father person = new Son();  //这个调用时合理的,因为子类就是父类,继承关系
        person.eat();
    }
}

2.4 动态绑定

❤️概念
让我们来思考一个问题,这里是用Father引用来调用的,但是呈现出来的结果确实调用了子类的 eat ,通过查看字节码文件发现,程序编译的时候确实调用了Father的eat,但是运行的结果是子类的

在编译时,不知道调用哪个方法,等到运行的时候,才能知道,这种过程叫做运行时绑定 / 动态绑定

❤️条件

  • 用父类的引用调用来调用这个重写的方法
  • 方法的重写

❤️方式

  • 直接赋值
Father person = new Son();
  • 传参
class Father{
    public void eat(Father person){
        System.out.println("吃饭");
    }
}

class Son extends  Father{
    public void eat(Father person){
        System.out.println("正在吃黄焖鸡米饭");
    }
}

public class Main {
    public static void main(String[] args) {
        Son person = new Son();
        person.eat(person);
    }
}
  • 返回值
class Son extends  Father{
    public Father eat(Son person){
        System.out.println("正在吃黄焖鸡米饭");
        return person;
    }
}

public class Main {
    public static void main(String[] args) {
        Son person = new Son();
        person.eat(person);
    }
}

三、扩展内容

3.1 静态绑定

在编译时,通过参数列表的个数、类型、大小等就可以确定是哪个方法,比如方法的重载

3.2 向下转型

概念:创建一个父类对象,用子类的引用来接收,从小范围变为了大范围
语法格式:子类类型 对象名 = new 父类类型()
注意点:

  • 除非是调用该子类对象的成员,否则不安全(理解:不是所有的动物都是狗,也可能是猫或其他,万一出现狗引用了猫情况,会报错)
  • instanceof,可以规避不安全的情况
  • 父类给子类需要强转
class Animal{
    String name;
    int age;

    public Animal(String name) {
        this.name = name;
    }
}

class Dog extends  Animal{
    public Dog(String name) {
        super(name);
    }

    public void bark(){
        System.out.println(this.name + "在汪汪叫");
    }
}

class Cat extends  Animal{
    public Cat(String name) {
        super(name);
    }

    public void mimi(){
        System.out.println(this.name + "在喵喵叫");
    }
}
public class Main{
    public static void main(String[] args) {
        Animal animal = new Dog("旺财");
        Dog dog = (Dog) animal;
        dog.bark();

        if (animal instanceof Cat){
            Animal animal2 = new Dog("旺财");
            Cat cat = (Cat) animal;
            cat.mimi();
        }
    }
}

在这里插入图片描述

3.3 代码的优缺点

❤️优点

  • 能够降低代码的 “圈复杂度”, 避免使用大量的 if - else
  • 可扩展能力更强(如果要新增一种新的形状, 使用多态的方式代码改动成本也比较低)

❤️缺陷

  • 属性没有多态性
    当父类和子类都有同名属性的时候,通过父类引用,只能引用父类自己的成员属性

  • 不能在构造方法中调用其他方法,可能导致还没有初始化完成,就执行其他方法,即成员变量还是默认值

二、注意点
每次调用方法都要进行搜索,时间开销相当大。因此,虚拟机预先为每个类创建了一个方法表( method table), 其中列出了所有方法的签名和实际调用的方法。这样一来,在真正调用方法的时候, 虚拟机仅查找这个表就行了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值