Java之多态

本文详细解释了Java中的多态概念,包括为什么使用多态,多态的基础(动态绑定),以及重写、向上转型和向下转型的原理、规则和应用场景。通过实例展示了如何在代码中实现多态,讨论了其优点和缺点,以及在构造方法中调用重写方法的风险。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、多态前言

1.为什么要使用多态

Java中使用多态的主要目的是提高代码的可重用性和扩展性,使得代码更加灵活和易于维护。通过多态,我们可以将不同的对象看做是同一种类型,从而使得我们可以使用同一种接口来操作这些对象,而不必关心具体的实现细节。

2.多态概念

当父类的引用所指向的子类对象引用指向的对象不一样时。调用重写的方法,所表现出来的行为是不一样的,我们把这种思想叫做多态。上面所说的可能大家会觉得有点抽象,看到后面就懂了。
多态的基础是动态绑定,所以要了解多态前提我们还要了解动态绑定。
要想实现动态绑定,需要满足以上几个条件:
1.要发生向上转型
2.要发生重写
3.使用父类对象的引用去调用重写方法
完成了这三部分,就会发生动态绑定,而在这里,出现了重写以及向上转型这些概念。所以我们得先了解它们才能去了解动态绑定。进而了解多态。

二、重写

1.重写的概念

重写(override):也称为覆盖。将父类的方法重新在子类中使用。 返回值和形参都不能改变即外壳不变,核心重写!重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。

方法重写的规则:
1.子类在重写父类的方法时,必须与父类方法原型一致:即返回值、方法名、参数列表要完全一致
2.被重写的方法的访问修饰限定符在子类中要大于等于父类的。
3.父类中被static或private或final修饰的方法以及构造方法都不能被重写。 
4.在子类中重写的方法, 可以使用 @Override 注解来显式指定. 有了这个注解能帮我们进行一些合法性校验。

2.重写的作用

对于已经投入使用的类,尽量不要进行修改。最好的方式是:重新定义一个新的类,来重复利用其中共性的内容,并且添加或者改动新的内容。
例如:若干年前的手机,只能打电话,发短信,来电显示只能显示号码,而今天的手机在来电显示的时候,不仅仅可以显示号码,还可以显示头像,地区等。在这个过程当中,我们 不应该在原来老的类上进行修改,因为原来的 类,可能还在有用户使用,正确做法是: 新建一个新手机的类,对来电显示这个方法重写就好了,这样就达到了我 们当今的需求了

三、向上转型

向上转型:实际就是创建一个子类对象,将其当成父类对象来使用。
语法格式:父类类型 对象名 = new 子类类型()
Animal animal = Dog();
我们对以上代码进行实质化分析,以上的代码其实是省略化了,见以下代码

Dog dog = new Dog();
 Animal animal = dog;//该代码发生了向上转换,将Dog对象转换为Animal类型

通过向上转型后,就可以父类对象名来访问子类的方法了。使用animal.eat();这语句来访问
这个语句发生了动态绑定(在编译过程中调用的其实是父类的eat,但是在运行时换为调用子类的eat了)故实现了创建一个子类对象,将其当成父类对象来使用。见以下代码

class Animal {

void sound() {

System.out.println("Animal makes a sound");

}

}

class Dog extends Animal {

 void sound() {

System.out.println("Dog barks");

}

 void fetch() {

System.out.println("Dog fetches a ball");

}

}

public class Main {

public static void main(String[] args) {

Dog dog = new Dog(); // 创建Dog对象

 Animal animal = dog; // 向上转型,将Dog对象转换为Animal类型

 animal.sound();//调用子类的覆盖方法

 // animal.fetch(); // 编译错误,因为Animal类中没有fetch方法

}

}

// 输出: Dog barks

通过以上代码发现一个问题,不能调用到子类特有的方法(因为编译时调用的是父类的方法),我们可以通过向下转型来调用到子类特有的方法(后面介绍)
静态绑定:也称为前期绑定(早绑定),即在编译时,根据用户所传递实参类型就确定了具体调用那个方法。典型代表函数重载。
动态绑定:也称为后期绑定(晚绑定),即在编译时,不能确定方法的行为,需要等到程序运行时,才能够确定具体调用那个类的方法。当发生重写时,通过父类调用该方法时会发生动态绑定。

向上转型 使用场景
1. 直接赋值
2. 方法传参
3. 方法返回
见以下代码

public class TestAnimal {

// 2. 方法传参:形参为父类型引用,可以接收任意子类的对象

public static void eatFood(Animal a){ //因为主方法的原因使用静态方法

a.eat();  //方法传参向上转型

}

// 3. 作返回值:返回任意子类对象的实例

public static Animal buyAnimal(String var){

return new Dog();

}

评论 104
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值