多态是面向对象编程思想的三大特性之一,我感觉这三大特性,多态最绕,学的时候绕来绕去,老难了。
好了睡了这么多,进入正题吧。
什么是多态
不同类的对象对同一消息做出的不同响应叫做多态。也就是说,同一个消息因为发送对象不同而做出不同的响应。
举个例子:
你爸给你说儿子给我捶捶背,你肯定是跑很快的去给老父亲捶背。
但是反过来,你给你爸说儿子给我捶捶背,你爸是啥反应?
虽然例子有点过分,但是我感觉这确确实实可以让人深刻的记住。
JAVA中多态存在的三个条件
1.有继承关系
2.子类重写父类的方法
以下类型的方法不能被重写,不能表现出多态性
(1)static修饰的方法,static修饰的方法属于类,不能被重写
(2)private修饰的方法,private修饰的方法对于子类不可见,不能重写
(3)final修饰的方法,我们知道final修饰的类不能被继承,那么同样的final修饰的方法不能被重写。
public class animal {
String name;
public animal(String name){
this.name = name;
}
public void eat(String food){
System.out.println(this.name+"是一个动物");
System.out.println(this.name+"喜欢吃"+food);
}
public final void sleep() {
System.out.println(this.name+"正在睡觉");
}
}
public class dog extends animal {
public dog(String name) {
super(name);
}
public void eat(String food) {
System.out.println(this.name+"是一条狗");
System.out.println(this.name+"喜欢吃"+food);
}
//报错,因为重写的方法是final修饰的
public final void sleep() {
}
}
直接上图:
3.父类引用指向子类对象(也就是当时让我很绕的向上转型)
动态绑定
先看个动态绑定的例子:
/*************父类*************/
public class animal {
String name;
public animal(String name){
this.name = name;
}
public void eat(String food){
System.out.println(this.name+"是一个动物");
System.out.println(this.name+"喜欢吃"+food);
}
}
/*************子类*************/
public class dog extends animal {
public dog(String name) {
super(name);
}
public void eat(String food) {
System.out.println(this.name+"是一条狗");
System.out.println(this.name+"喜欢吃"+food);
}
}
/*************测试*************/
public class test {
public static void main(String[] args){
animal a = new animal("大黄");
a.eat("骨头");
animal b = new dog("大黑");//向上转型
b.eat("骨头");
}
}
运行结果:
- 我们可以发现a和b虽然都是animal的引用,但是它们指向的实例化对象不同,a指向的是animal的对象,b指向的是dog的对象。
- 对a和b都调用eat方法,发现a调用的是animal.eat()方法,而b调用的是dog.eat()方法。
这种在运行过程中,根据引用指向的对象来确定调用那个方法的手段,这就叫动态绑定。
多态的一个实例
package Demo1;
import java.awt.*;
class shape{
public void draw() {
System.out.println("哈哈");
}
}
class cycle extends shape{
@Override
public void draw() {
System.out.println("我画了一个⚪");
}
}
class heart extends shape{
@Override
public void draw() {
System.out.println("我画了一个♥");
}
}
class flower extends shape{
@Override
public void draw() {
System.out.println("我画了一个♣");
}
}
public class test {
public static void main(String[] args){
shape s1 = new cycle();
shape s2 = new heart();
shape s3 = new flower();
drawShape(s1);
drawShape(s2);
drawShape(s3);
}
public static void drawShape(shape shape) {
shape.draw();
}
}
结果:
对于多态,在具体一点就是“一个引用可以表现不同形态”。
使用多态的好处
- 1.类的调用者对于类的使用成本进一步降低
封装是让类的调用者不需要知道类的实现细节。
多态能让类的调用者连这个类的类型是什么都不必知道, 只需要知道这个对象具有某个方法。 - 2.可以降低代码的圈复杂度,避免使用大量if-else
例如现在我们不打印一个形状,我们打印多个形状,不使用多态代码如下:
public static void drawShapes() {
cycle cycle = new cycle();
heart heart = new heart();
flower flower = new flower();
String[] shapes = {"cycle","heart","cycle","flower"};
for (String shape : shapes) {
if (shape.equals("cycle")) {
cycle.draw();
}else if (shape.equals("flower")) {
flower.draw();
}else if (shape.equals("heart")) {
heart.draw();
}
}
}
如果使用多态,就不用这么麻烦的频繁使用if-else,代码如下:
public static void drawShapes() {
shape[] shapes = {new cycle(),new heart(),new flower()};
for (shape shape : shapes) {
shape.draw();
}
}
那个好用,一目了然。
- 3.可拓展能力强
如果要新增一种新的形状, 使用多态的方式代码改动成本也比较低。
class rect extends shape{
@Override
public void draw() {
System.out.println("我画了一个♦");
}
}
对于类的调用者来说,只需要创建一个新类的实例就可以了,如果不用多态,那么又要对if-else的内容进行修改,改动成本很高。