Java中多态的作用

1 多态


#多态 不同的对象去完成具体的某个行为,产生不同的状态

1.1 方法重写(Override)

重写(override):也称为覆盖。方法重写是发生在继承体系下的一种机制,即重写发生在子类与父类间。当父类和子类中存在返回值和形参没有差异,方法名相同的方法时,我们说这个方法发生了重写,实现了方法重写。

//我们以一段代码块引入:
public class Animal {
	//成员变量
	public String name;
	int age;
	//成员方法
	public Animal(String name) {
		this.name = name;
	}
	public void eat() {
		System.out.println(this.name + "正在吃饭...");
	}
	
	
}

//Dog.java
public class Dog extends Animal{
	public Dog(String name) {
		super(name);
	}
	public void bark() {
		System.out.println(this.name + "正在汪汪叫...");
	}
	@Override
	public void eat() {
		System.out.println(this.name + "正在吃狗粮...");
	}
	
}

//Cat.java
public class Cat extends Animal{
	public Cat(String name) {
		super(name);
	}
	public void meow() {
		System.out.println(this.name + "正在喵喵叫...");
	}
	@Override
	public void eat() {
		System.out.println(this.name + "正在吃猫粮...");
	}
	
}

观察上述代码,我们发现Dog类和Cat类都继承于Animal类,在Animal类和它的子类Dog和Cat中都存在eat()方法,且返回值形参一致,这时候我们说Dog类和Cat类分别对Animal父类进行了eat()方法的重写。

  • 方法重写的规则
  • 子类重写父类方法时,一般要求子类方法必须与父类方法原型一致:返回值类型 方法名 (参数列表) 完全一致
  • 被重写的方法返回类型可以不同,但必须与父类的返回值类型具有父子关系
  • 重写方法的访问权限不能比父类中被重写方法的访问权限更低
  • 不能重写父类中被staticprivatefinal修饰的方法
  • 不能重写构造方法
  • 重写的方法可以用@Override来显示注解,这个注解能帮我们进行一些合法校验,校验被其注解的方法是不是重写方法

//Main.java
public class Main {
	public static void main(String[] args) {
		Animal animal1 = new Animal("小白");
		Animal animal2 = new Dog("大黄");
		Animal animal3 = new Cat("小黑");
		//分别通过三个引用调用eat()方法
		animal1.eat();
		animal2.eat();
		animal2.eat();
		
	}
} 

分析上述代码,运行结果如下:
小白正在吃饭…
大黄正在吃狗粮…
小黑正在吃猫粮…

我们发现三者引用对象不同,调用eat()方法的输出结果也不同,这种现象叫多态,所以方法重写是发生多态的条件之一。

1.2 向上转型和向下转型

1.2.1 向上转型

在上文发生多态的代码中,我们发现Animal类的引用接收了不同类型的引用,那么什么是向上转型呢?

向上转型:父类引用 引用 子类对象
语法格式: 父类类型 引用变量 = new 子类类型(…);
在这里插入图片描述

需要注意的是:当发生向上转型时,我们就将父类引用接收的子类对象当作父类对象去使用,这时候我们不能调用子类中独有的方法

1.2.2 向下转型

我们知道将一个子类对象经过向上转型之后当作父类对象去使用,这时我们无法在通过这个父类引用去调用子类特有的方法,当我们需要调用子类中特有的方法,又该如何去做呢?

向下转型: 将父类引用还原为子类对象
Animal animal2 = new Dog(“大黄”);//向上转型
要调用狗类中的bark()方法
//直接借助animal2调用,会出现编译失败
animal2.bark();//error,animal2为Animal对象

//这时候我们就可以借助向下转型来实现
Dog dog = (Dog)animal2;
dog.bark();//编译通过,dog为Dog对象,存在bark()方法

我们发现在向下转型的过程中,我们借助了强转(),也就是说向下转型是大类型(父类)向小类型(子类)的转换,这种大类型向小类型的转换之间往往存在着风险,这时候我们往往需要确定这种转换是被允许的,因此我们引出instanceof关键字

Animal animal2 = new Dog("大黄");//向上转型
//animal2 instanceof Dog
//用来判断animal2 引用的对象类型是不是Dog
if(animal2 instanceof Dog) {
	Dog dog = (Dog)animal2;//强转前判断是否能够强转
	dog.bark();
}else {
	System.out.println("无法转换");
}

1.3 动态绑定

#静态绑定 也称为前期绑定,即在编译时,根据用户所传递实参类型就确定了具体调用那个方法了,如方法重载(Overload)

#动态绑定 动态绑定指的是在调用对象的方法时,根据对象的实际类型来决定调用哪个方法的过程。这意味着编译器或解释器在运行时根据对象的实际类型动态地决定要调用的方法实现,而不是在编译时确定。

其实在我们前面的学习中,我们已经初步见识了动态绑定机
制,上文通过三个引用对象不同的Animal引用,在调用eat()方法时出现的不同现象实际就是由于动态绑定引起的

Animal animal1 = new Animal("小白");
Animal animal2 = new Dog("大黄");
Animal animal3 = new Cat("小黑");
//分别通过三个引用调用eat()方法
animal1.eat();
animal2.eat();
animal2.eat();

//在编译时,我们看=左边的类型确定了只能使用Animal中的方法
//eat()方法发生了重写
//运行时我们会根据具体引用对象的类型来决定调用那个类的
//eat()方法;

这就是动态绑定机制。

总结来说,动态绑定有以下特点:

  • 当调用对象方法时,该方法会和该对象的内存地址/运行类型绑定
  • 对于对象属性来说没有动态绑定机制,使用就近原则

1.4 多态发生的条件和优点

条件:

  • 继承体系下
  • 发生方法重写
  • 向上转型和动态绑定

优点:

  • 降低代码的圈复杂度,避免大量使用if-else

#圈复杂度 圈复杂度是一种描述一段代码复杂程度的方式. 一段代码如果平铺直叙, 那么就比较简单容易理解. 而如果有很多的条件分支或者循环语句, 就认为理解起来更复杂.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值