方法或对象具有多种形态,多态是建立在封装和继承继承之上的,前提是两个对象(类)存在继承关系
重写和重载就体现了多态,对象的多态是核心
重要:
1)一个对象的编译类型和运行类型可以不一致
(Dog是子类,Animal是父类)
Animal animal = new Dog();【animal 编译类型是Animal,运行类型是Dog】
2)编译类型在定义对象时就确定了,不能改变
3)运行类型是可以改变的
4)编译类型看定义时 = 号左边,运行类型看 = 号右边
向上转型
本质:父类的引用指向子类的对象
语法:父类类型 引用名 = new 子类类型();
特定:编译类型看左边,运行类型看右边。可以调用父类中的所有成员(需遵循访问权限),不能调用子类中特有成员(因为在编译阶段能调用哪些成员由编译类型决定,e.g. 不能调用猫抓老鼠的方法),最终运行效果看子类的具体实现(调用方法时,从子类开始查找方法,然后调用,和之前讲的方法调用规则一致)
向下转型
语法:子类类型 引用名 = (子类类型) 父类引用;
只能强转父类的引用,不能强转父类的对象
要求父类的引用必须指向的是当前目标类型的对象
可以调用子类类型中所有的成员
结合向上转型的代码,animal 已经指向 Cat 对象,所以 animal 可以再转成 Cat,但不能转成 Dog
多态的注意事项和细节:
1)方法可以重写,但属性无法重写
2)instanceOf 比较操作符,用于判断对象的运行类型是否为XX类型或XX类型的子类型
TRUE
TRUE
练习:
JAVA 的动态绑定机制(重要)
1)当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定
2)当调用对象属性时,没有动态绑定机制,哪里声明哪里使用
当注释掉子类的 sum() 后,由于 a 的运行类型是 B ,所以调用子类的 getI 方法,所以 a.sum() 的结果为 30
当注释掉子类的 sum1() 后,a.sum1() 的结果为 20
多态的应用
多态数组
数组的定义类型为父类类型,里面保存的实际元素类型为子类类型
应用实例:
应用实例升级:类型判断+向下转型
多态参数
方法定义的形参类型为父类类型,实参类型允许为子类类型
应用实例1:主人喂小动物
应用实例2:
上图还有get和set方法没截下来
上图还有get和set方法没截下来