引出
传统的方法:代码复用性不高,不利于管理和维护
解决方法:多态
- 多【多种】态【状态】:(方法或对象具有多种形态,面向对象的第三大特征,建立于封装、继承之上)
一、方法的多态
1.重写和重载就体现多态
重载:
A a=new A();
System.out.print(a.sum(10,30));
System.out.print(a.sum(10,30,50));
重写:
B b=new B();
System.out.print(b.say("hi"));
A obja= new A();
System.out.print(obja.say("ok"));
//对象不一样调用的方法不一样
二、对象的多态(核心)
1.一个对象的编译类型和运行类型可以不一样
2.编译类型在定义对象时就确定了,所以不能改变
3.=左编译,=右运行,编译不变,运行可变
Animal animal=new Cat();
//animal 编译对象是 Aniaml ,运行类型 Cat
animal.cry();
//animal运行类型是Cat,所以cry就是Cat的cry
animal=new Dog();
//animal运行类型为Animal,运行类型为Dog
animal.cry();
//animal运行类型是Doy,所以cry就是Doy的cry
三、向上转型
- 定义:父类的引用指向了子类的对象
- 语法:父类类型 引用名 = new 子类类型引用名
//语法:父类类型 引用名 = new 子类类型引用名
Animal animal=new Cat();
Object obj=new Cat();
//可以吗? 可以,Object是所有父类的爷爷
- 向上转型调用规则:
1. 可以调用父类中的所有成员(需遵守访问权限)
2. 但是不能调用子类的特有的成员
(因为在编译阶段,能调用哪些成员,是由编译类型来决定的)
3. 最终运行效果看子(运行类型)的具体实现,即调用方法时,按照从子类(运行类型)开始查找方法然后调用,规则与方法调用规则一致。
四、向下转型
- 作用:当向下转型后,可以调用子类类型中所有的成员
- 语法:子类类型 引用名=(子类类型)父类引用
//语法:子类类型 引用名 =(子类类型)父类引用
Cat cat=(Cat)animal;
-
向下转型调用规则(注意事项):
1.只能强转父类的引用,不能强转父类的对象
2.要求父类的引用必须指向的是当前目标类型的对象- 强转条件是:父类引用指向的是当前要强转后的目标类型的对象 - 区分:向上转型是父类引用指向子类对象,能调用父类成员,向下转型是父类引用强转子类引用并指向子类对象,可以调用全部子类成员
五、属性重写 / instanceof
- 属性没有重写:属性的值看编译类型
Animal animal=new Cat();//Animal为编译类型
System.out.print(animal.a);//111
____________________________________________________________
class Animal{
int a=111;
}
class Cat extends Animal {
int a=222;
}
- instanceof(比较操作符):用于判断对象的运行类型是否为XX类型或XX类型的子类型
BB bb=new BB();
Object obj2=null;
System.out.print(bb instanceof AA);//(true)其中A是B的父类
System.out.print(obj2 instanceof AA);//(false)Object是所有类的爷爷
* 练习小结
1.属性看编译,方法看运行
2.两个对象比较的是地址
六、动态绑定机制(炒鸡重要!!)
1.当调用对象方法的时候,该方法会和该对象的
存地址/运行类型绑定
2.当调用对象属性时,没有动态绑定机制,哪里声
明,那里使用
- 属性静态看编译类型(父类)(属性无多态),属性动态无绑定,服从就近原则。
方法静态看运行类型(子类,表现出多态),方法动态绑定运行类型。
七、多态应用–多态数组
- 定义:数组的定义类型为父类类型,里面保存的实际元素类型为子类类型
- (遍历数组输出)
(使用类型判断+向下转型来调用子类特有的方法)
八、多态应用–多态参数
- 方法定义的形参类型为父类参数,实参类型允许为子类类型