面向对象三大特征之一,编译类型和运行类型不一致,这种现象叫做多态
定义
某一类事物的多种存在形态
- 例:动物中猫,狗
- 猫这个对象对应的类型是猫类型
- 猫x = new 猫();
- 同时猫也是动物中的一种,也可以把猫称为动物
- 动物 y = new 猫();
- 动物是猫和狗具体事物中抽取出来的父类型
- 父类型引用指向了子类对象
理解
体现:父类或者接口的引用指向或者接收自己的子类对象
作用:多态的存在提高了程序的扩展性和后期可维护性
前提:
- 需要存在继承或者实现关系
- 要有覆盖操作
好处:多态的出现大大的提高程序的扩展性
弊端:提高了扩展性,但是只能使用父类的引用访问父类中的成员
特点
非静态成员函数:
- 编译时:要查看引用变量所属的类中是否有所调用的成员
- 在运行时:要查看对象所属的类中是否有所调用的成员
成员函数在多态调用时,编译看左边,运行看右边
成员变量:
- 只看引用变量所属的类
静态成员:
- 只看引用变量所属的类
多态
class BaseClass{···}
class SubClass extends BaseClass{···}
···
BaseClass bc = new SubClass();
···
-
在上述示例中,将子类的对象赋值给父类,这叫做向上转型,由系统自动完成。bc在编译时候属于BaseClass类型,而运行时候则为SubClass类型,这就出现了多态。当bc调用实例变量时,将调用父类的实例变量,这是由于对象的实例变量不具备多态性,bc只可以调用父类中存在的方法,但是是在子类中调用,若子类重写了父类的方法,那么调用的就是被重写后的方法,如果没被重写,那么就直接调用继承到的方法,对于仅仅存在于子类中的方法,若使用bc去调用,那么则会编译报错
-
多态:相同类型的变量、调用同一个方法时呈现出多种不同的行为特征,这就是多态
-
引用类型之间的转换只能在具有继承关系的两个类型之间,如果试图把一个父类实例转化成子类类型,则这个对象必须实际上是子类类型才可以(即编译类型为父类类型,而运行类型为子类类型)
-
instanceof:为了避免ClassCastException异常,使用instanceof先进行判断在进行类型转换。instanceof前一个操作数通常为一个引用类型变量,后一个操作数通常是一个类(也可以是接口),用于判断前面的对象是否是后面的类或者其子类、实现的实例。如果是则返回true,否则返回false。如果instanceof运算符前面的操作数的编译类型与后面的类不同,或者与后面的类不具备父子继承关系,则会引起编译错误
if ( objPri instanceof String )
{
String str = (String) objPri;
}
转型
能转换的是父类应用指向了自己的子类对象时,该应用可以被提升,也可以被强制转换
多态自始至终都是子类对象在做着变化
在多态中存在着转型操作,通常称为向上转型和向下转型
例如存在Cat继承自Animal
那么,将一个Cat对象赋值给Animal就属于向上转型
Animal animal = new Cat(); //向上转型
如果将父类引用转化为子类类型,这种现象称之为向下转型
Cat cat = (Cat)animal; //向下转型
instanceof关键字
用于判断对象的类型
格式:
对象 intanceof 类型(类类型 接口类型)
public static void func(Animal a) {
if(a instanceof Cat){
Cat c = (Cat)a;
···
}
}
多态实例
interface PCI {
public void open();
public void close();
}
class MainBoard{
public void run() {
System.out.println("mainboard run ");
}
public void usePCI(PCI p) {
if(p != null){
p.open();
p.close();
}
}
}
class NetCard implements PCI {
public void open() {
System.out.println("netcard open");
}
public void close(){
System.out.println("netcard close");
method();
}
}
class SoundCard implements PCI {
public void open() {
System.out.println("SoundCard open");
}
public void close() {
System.out.println("SoundCard close");
}
}
class Test
{
public static void main(String[] args) {
MainBoard mb = new MainBoard();
mb.run();
mb.usePCI(null);
mb.usePCI(new NetCard());
mb.usePCI(new SoundCard());
}
}