多态性,是面向对象中最重要的概念,在java中有两种体现:
方法的重载(overload)和重写(overwrite)。
对象的多态性——可以直接应用在抽象类和接口上。
java引用变量有两个类型:编译时类型和运行时类型。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。
若编译时类型和运行时类型不一致,就出现多态(polymorphism)。
对象的多态,在java中,子类的对象可以替代父类的对象使用
一个变量只能有一种确定的数据类型。
一个引用类型变量可能指向(引用)多种不同类型的对象。
Person p = new Student();//Person类型的变量p,指向Student类型的对象。
子类可看做是特殊的父类,所以父类类型的引用可以指向子类的对象:向上转型(upcasting)(子类的对象可以被父类的引用变量使用)。
一个引用类型变量如果声明为父类的类型,但实际引用的是子类对象,那么该变量就不能再访问子类中添加的属性和方法。
Student m = new Student();
m.school = "pku"; //合法,Student类有school成员变量
Person e = new Student();
e.school = "pku"; //非法,Person类没有school成员变量
属性是在编译时确定的,编译时e为Person类型,没有school成员变量,所以编译错误。
虚拟方法调用
编译时e为Person类型,而方法的调用是在运行时确定的,所以调用的是Student类的方法。
java的方法时运行在栈内存中的,运行方法时会动态进栈和出栈。
多态小结
前提:需要存在继承或实现关系。要有覆盖操作。
成员方法:成员方法的多态性,也就是动态绑定,必须得存在与方法的重写之上。
编译时:要查看引用变量所属的类中是否有所调用的方法。
运行时:调用实际对象所属的类中的重写方法。
成员变量:不具备多态性,只看引用变量所属的类。
子类继承父类
若子类重写了父类方法,就意味着子类里定义的方法彻底覆盖了父类里的同名方法,系统将不可能把父类里的方法转移到子类中。
对于实例变量则不存在这样的现象,即使子类里定义了和父类完全相同的实例变量,这个实例变量依然不可能覆盖父类中定义的实例变量。
多态性应用举例
方法声明的形参类型为父类类型,可以使用子类的对象作为实参调用该方法。