"多态"是java语言的三大特征之一。
"多态"的含义是同一个行为具有多个不同表现形式或形态的能力,或者说就是同一个接口,使用不同的实例而执行不同操作。
“多态"是程序在执行过程中的一种"动态绑定"行为,所谓的"动态绑定”,简单说就是对象在不同情况下有不同的表现行为。
正文:
1. 多态的表现形式
“多态"的表现形式可以简单的总结为"两个方法,三个定义”:
- “两个方法”:方法重载,方法重写;
- “三个定义”:父类定义子类构建,接口定义类实现,抽象类定义实体类实现。
简单的理解就是,多态有三种实现方式,即:实体类的重写重载,接口的实现,抽象类的继承;
2. 多态的优点
- 消除类型之间的耦合关系
- 可替换性
- 可扩充性
- 接口性
- 灵活性
- 简化性
3. instanceof 关键字
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法。
多态的好处:可以使程序有良好的扩展,并可以对所有类的对象进行通用处理。
以下是一个多态实例的演示,详细说明请看注释:
public class Test {
public static void main(String[] args) {
Animal a = new Animal ();
Cat cat = new Cat ();
Dog dog = new Dog ();
a.show(cat); // 调用cat方法
a.show(dog); // 调用dog方法
}
public static void show(Animal a) {
// 类型判断
if (a instanceof Cat) { // 猫做的事情
Cat c = (Cat)a; // 向下造型
c.work();
} else if (a instanceof Dog) { // 狗做的事情
Dog c = (Dog)a; // 向下造型
c.work();
}
}
}
// Animal 类、Cat 类、 Dog 类 此处省略...
4. 动态绑定
我们已经讨论了方法的重写,也就是子类能够重写父类的方法。
当子类对象调用重写的方法时,调用的是子类的方法,而不是父类中被重写的方法。
要想调用父类中被重写的方法,则必须使用关键字super。
/* 文件名 : Employee.java */
public class Employee{
private int id;
private String name;
public Employee(int id, String name) {
System.out.println("Animal 的构造函数");
this.id = id;
this.name = name;
}
public void check() {
System.out.println("我的基本信息:" + this.id
+ " " + this.name);
}
public String toString() {
return id + " " + name;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public void setId(int newId) {
id = newId;
}
public void setName(String newName) {
name = newName;
}
}
/* 文件名 : Weight.java */
public class Weight extends Employee {
private double weight; // 全年工资
public Food (int id, String name, double weight) {
super(id, name);
setWeight(weight);
}
public double getWeight() {
return weight;
}
public void check() {
System.out.println("Weight类的 check方法");
System.out.println("体检对象是:" + getName()
+ " ,体重为:" + weight);
}
public void setWeight(double newWeight) {
if(newWeight >= 0.0) {
weight = newWeight;
}else{
System.out.println("体重数值异常");
}
}
}
/* 文件名 : CheckDemo.java */
public class CheckDemo{
public static void main(String [] args) {
Weight a = new Weight(1, "小猫", 10.5);
Employee b = new Weight(2, "小狗", 21.1); //向上造型
System.out.println("使用 Weight 的引用调用 check -- ");
a.check();
System.out.println("使用 Employee 的引用调用 check--");
b.check();
}
}
//输出结果:
Employee 的构造函数
Employee 的构造函数
使用 Weight 的引用调用 check --
Weight类的 check方法
体检对象是:小猫 ,体重为:10.5
使用 Employee 的引用调用 check--
Weight类的 check方法
体检对象是:小狗 ,体重为:21.1
上面的实例是一个典型的"多态"应用,调用的方法在运行时进行了"动态绑定"。
例子解析
- 当调用 a.check() 时,编译器在编译时会在 Weight 类中找到 check(),执行过程 JVM 就调用 Weight 类的 check();
- 当调用 b.check() ,因为 b 是 Employee 的引用,所以调用 b 的 check() 方法时,编译器会去 Employee 类查找 check() 方法,使用 Employee 类中的 check() 方法验证该语句,但是在执行的时候,Java虚拟机(JVM)调用的是 Weight 类中的 check() 方法。
Java中所有的方法都能以这种方式表现,因此,重写的方法能在运行时调用,不管编译的时候源代码中引用变量是什么数据类型。
有"动态绑定"自然就有"静态绑定",所谓的"静态绑定"是在类定义完之后就确定了方法的绑定。做法就是父类的方法上加静态关键字"static",确保每次造型调用的都是父类方法,子类重写也没用(即所谓的父类静态方法不可以重写):
public class Animal{
...
public static void check() {
System.out.println("我的基本信息:" + this.id
+ " " + this.name);
}
...
}
小结
- 多态的表现形式有"两个方法,三个定义";
- 构造器不可以重写,但可以重载,它也是多态的表现形式;
- "三个定义"中的对象只能使用声明时类型中的方法,不能使用自己的独特方法;
- 如果要使用自己的方法,则需要进行"强制类型转换",通常在进行"强制类型转换"时,需要使用"instanceof"运算符;
- 要想调用父类中被重写的方法,则必须使用关键字super。
更多精彩,请关注我的"今日头条号":Java云笔记
随时随地,让你拥有最新,最便捷的掌上云服务