前提:
需要存在继承或者实现关系(继承)
要有覆盖操作(方法的重写)
成员方法:
(成员变量的多态性,也就是动态绑定,必须存在于方法的重写之上)
编译时:要查看引用变量所属类中是否有所调用的方法(编译时要看父类是否定义了这个资源)
运行时:调用实际对象所属的类中的重写方法(运行时使用的是子类的功能)
如果方法重写了,成员方法的定义使用的是父类的,实现(方法体)使用的是子类的
成员变量:
不具备多态性,只看引用变量所属的类
多态中,成员变量都是父类的
多态性在java中的两种体现:
1、方法的重载(overload)和重写(overwrite)
2、对象的多态性–可以直接应用在抽象类和接口上
java引用变量有两个类型:
编译时类型和运行时类型。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。
对象的多态:若编译时类型和运行时类型不一致,就出现了多态
向上转型:
在java中,子类的对象可以替代父类的对象使用
1、一个变量只能有一种确定的数据类型
2、一个引用类型变量可能指向(引用)多种不同类型的对象
Person e = new Student(); //Person类型的变量e,指向Student类型的对象
编译期类型 运行时类型
属性是在编译时确定的,编译时p为Person类型,没有school成员变量,因而编译错误
多态中,编译看左边,运行看右边
子类可以看作是特殊的父类,所以父类类型的引用可以指向子类的对象:向上转型(upcasting)
一个引用变量类型如果声明为父类的类型,但实际引用的是子类对象,
那么该变量就不能再访问子类中添加的属性和方法
向下转型(较少):
子类的引用的指向子类对象,过程中必须要采取到强制转型。
Parent p = new Child();//向上转型,此时,p是Parent类型
Child c = (Child) p;//此时,把Parent类型的p转成小类型Child
//其实,相当于创建了一个子类对象一样,可以用父类的,也可以用自己的
说明:向下转型时,是为了方便使用子类的特殊方法,也就是说当子类方法做了功能拓展,就可以直接使用子类功能
虚拟方法调用:
Person e = new Student();
e.getInfo(); //如果Student类中有对getInfo()方法的重写,则调用此方法
//如果没有重写,则调用父类Person中的getInfo方法
编译时e为Person类型,而方法的调用是在运行时确定的,
所以调用的是Student类的getInfo();方法。–动态绑定
子类继承父类:
若子类重写了父类方法,就意味着子类里定义的方法彻底覆盖率父类里的同名方法,
系统将不可能把父类里的方法转移到子类中
对于实例变量(不以static修饰的成员变量)则不存在这样的现象,即使子类里定义了
与父类完全相同的实例变量,这个实例便利依然不可能覆盖父类中定义的实例变量
多态的好处:
多态可以让我们不用关心对象到底具体是什么类型,就可以使用该对象的某些方法
提高了程序的可扩展性和可维护性
instanceof关键字:
x instanceof a:检验x是否为类a的对象,返回值为boolean型
x所属类与类a必须是父子关系
x属于类a的子类,结果也为ture
注意:
静态方法不存在重写现象,可被类名直接调用,属于类的资源
Person e = new Student();
e.静态方法; //若Person于Student有同名静态方法,调用的是Person类的静态方法
多态中,如果父子类都有静态重名方法这个不是重写现象
所以静态方法调用的是父类的实现(方法体)
总结:
Person e = new Student();
多态中,只有重写的方法体是子类的,其他都在父类里(静态方法没有重写)