- 定义:一个对象具备多种形态,也可以理解为事物存在的多种体现形态。如果一个方法的参数类型是父类,可以向该方法的参数传递任何子类的对象,基类型对象可以访问派生类重写的方法,这称为多态。
(循环调用基类对象,访问不同派生类方法)
(实参是派生类,行参是基类)
- 实现多态的条件:
(1)继承:必须有子类继承父类的关系。
(2)方法重写:方法重写发生在具有继承关系的不同类中,子类会重写父类中的一些方法,调用方法时就会调用子类重写的方法而非父类的方法。
(3)向上转型(upcasting):在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够调用父类的方法和子类的方法。
3.向上转型的实例与解释:
public class Human {
public void sleep() {
System.out.println("Human sleep...");
}
public static void main(String[] args) {
Male m = new Male();
m.sleep();
Human h = new Male(); // 向上转型
h.sleep(); // 动态绑定
// h.speak();不能编译,因为在Human中没有speak方法
}
}
class Male extends Human{
@Override
public void sleep() {
System.out.println("Male sleep...");
}
public void speak( ) {
System.out.println("I am Male");
}
}
class Female extends Human{
@Override
public void sleep() {
System.out.println("Female sleep...");
}
public void speak( ) {
System.out.println("I am Female");
}
}
运行结果:
向上转型中有需要注意的点:
(1):向上转型不要强制转型
(2):父类引用指向的或者调用的方法是子类的方法,此为动态绑定。
(3):向上转型后父类引用不能调用子类自己的方法。
4.向下转型:
public class Human {
public void sleep() {
System.out.println("Human sleep...");
}
public static void main(String[] args) {
// (1) 向上转型
Male m1 = new Male();
Human h1 = m1;
h1.sleep();
//h1.speak; //此时需要向下转型,否则不能调用speak方法
// (2) 向下转型
Male m2 = new Male();
Human h2 = m2;
m2 = (Male)h2;
m2.speak();
//
// // (3) 向下转型,失败
// Human h3 = new Human();
// Male m3 = (Male)h3;
// m3.speak(); //此时会出现运行时错误,所以可以用instanceOF判断
//
// // (4) 向下转型,类型防护
// Human h3 = new Human();
// if(h4 instanceOf Male){ //因为h4不是Male的实例,所以不执行if内部代码
// Male m4 = (Male)h4;
// m4.speak();
// }
}
}
class Male extends Human{
@Override
public void sleep() {
System.out.println("Male sleep...");
}
public void speak( ) {
System.out.println("I am Male");
}
}
向下转型必须要在向上转型之后
5.动态绑定:
动态绑定与多态:多态是动态绑定的使用,动态绑定是多态的实现原理。
动态绑定的工作机制如下:
假设对象o是类C1,C2,…,Cn-1,Cn的实例,其中C1是C2的子类,C2是C3的子类,…,Cn-1是Cn的子类。也就是说,Cn是最通用的类,C1是最特殊的类。在Java中,Cn是Object类。如果对象o调用一个方法p,那么JVM会依次在类C1,C2,…,Cn-1,Cn中查找方法p的实现,直到找到为止。一旦找到一个实现,就停止查找,然后调用这个首先找到的实现。
6.抽象类与抽象方法:
(1)概念:抽象类用来描述一种类型应该具备的基本特征和功能,具体如何去完成这些行为由子类通过方法重写来完成,抽象方法只有功能声明,没有功能主体实现的方法,具有抽象方法的类一定为抽象类。
(2)定义:在Java语言中通过abstract关键词定义抽象类与抽象方法
一个抽象方法只有方法头,没有方法主体。
访问修饰符 abstract 返回类型 方法名(参数列表);
例如:public abstract void getArea();
抽象类:
例如:public abstract class 类名
(3)注意:
包含抽象方法的类就会自动变成抽象类,因此必须通过以abstract关键字声明。
如果派生类没有重写抽象方法,编译器会报错。
抽象方法被用来确保派生类会实现这个方法。
抽象类可以含零至多个普通方法,也可以含零至多个抽象方法。
不论抽象类是否含抽象方法,其都不允许实例化,即不能创建抽象类的对象,因为其描述的是抽象概念。它只能作为其他类的基类。
若父类为抽象类,且子类不想成为抽象类,则子类必须将父类中所有的抽象方法均重写为带方法体的普通方法,否则子类仍必须为抽象类。
参考文献:梁勇. Java语言程序设计与数据结构基础篇[M]. 北京:机械工业出版社,2018.167-175