多态性
引入:传统的方法(形参为不同类,就要新建不同的方法)代码复用性不高,不利于代码维护
多(多种)态(状态):方法或对象具有多种形态
多态的具体体现:
-
方法的多态
方法的重载和重写都体现了多态
-
对象的多态
对象的多态
一个对象的编译类型和运行类型可以不一致,编译类型在定义对象时就确定了,不能改变,而运行类型可以变化,编译类型看定义时“=”的左边,运行类型看”=“的右边
编译类型和运行类型
Animal animal = new Dog(); //编译类型为Animal,运行类型为Dog
animal = new Cat(); //animal的编译类型仍为Animal,但运行类型为Cat父类的引用指向子类的对象(或子类的对象赋给父类的引用)
person p = new student();
向上转型
本质:父类的引用指向子类的对象
语法:
父类类型 引用名 = new 子类类型();
特点:
-
可以调用父类中的所有成员(需遵守访问权限)
-
不能调用子类的特有成员
Animal animal = new Cat(); //只能调用Animal中的方法,不能调用Cat类中的特有方法解释:在编译阶段,对象能调用哪些成员由编译类型决定,比如上例中在编译阶段编译器认为animal的类型为Animal,因此只能调用Animal中的成员,如果调用Cat类中的特有方法将不能被编译器识别

-
一旦编译成功,进入运行阶段,那么将会依据对象的运行类型,在调用方法时从运行类型处开始查找方法,如果运行类型中没有声明此方法,则在向上(父类中)寻找,直至找到Object类。因此一旦子类中重写了父类的方法,那么由于先从子类中查找声明方法,因此会执行该重写的方法。
向下转型
语法:
子类类型 引用名 = (子类类型)父类引用
特点:
-
只能强转父类的引用,不能强转父类的对象
-
要求父类的引用必须指向的是目标子类类型的对象(父类引用的运行类型为什么类型,向下转型才能转为哪个类型)
Animal animal = new cat();//父类引用animal //向下转型 Cat cat = (Cat)animal;//目标子类类型Cat Dog dog =(Dog)animal;//报错 -
向下转型后可以调用子类类型中所有的成员
属性问题
属性的值由编译类型决定
class Animal{
int ID = 1;
}
class Cat{
int ID = 2;
}
Animal animal = new Cat();
int ID=animal.ID //ID=1
动态绑定机制
- 当调用对象方法时, 方法会和该对象的内存地址/运行类型绑定
- 当调用对象属性时,没有动态绑定机制,哪里声明使用哪里的属性值
public class A{
int i = 10 ;
public int sum(){
return 10+getsum();
}
public int getsum(){
return i
}
}
public class B extends A{
int i = 20;
public int getsum(){
return i
}
}
public class test{
public static void main(String[] args){
A a = new B();
int isum=a.sum();
//isum=30。首先在运行类型B中看是否有sum方法,没有向父类中寻找
//父类中的sum方法中又涉及到getsum()方法,而子类和父类都有这个方法
//由动态绑定机制知,方法会和对象的运行类型绑定,因此会从运行类型B处寻找该方法
//getsum返回结果20
}
}
多态应用
多态数组
数组的声明类型为父类类型,但里面保存的元素类型为父类/子类类型

需要注意的时,子类对象不能调用自己特有的方法,如果需要调用特有方法,需要进行向下类型转换
多态参数
方法定义的形参为父类类型,实参类型可以为子类类型

对于对象p,如果想调用其方法时,只能调用父类中所声明的方法,但是如果子类中对父类中方法进行重写,那么则会调用子类中重写的方法,而对于子类中单独声明的方法则不能被调用。因此应用多态性需满足两个前提条件:①类的继承②子类中有重写的方法。
对象的多态性只适合于方法,不适用于属性
//举例1
class Test{
public static void main(String[] args){
Test t = new Test();
t.test(new Dog());
t.test(new Cat());
}
//多态性体现:父类对应多个子类,作为函数形参多个子类都可传入到函数中,而不需要创建多个不同函数形参的函数
public void test(Animal animal){
animal.eat();
}
}
public class Animal{
public void eat(){
System.out.println("吃饭!");
}
}
public class Dog extends Animal{
public void eat(){
System.out.println("吃骨头!");
}
}
public class Cat extends Animal{
public void eat(){
System.out.println("吃鱼!");
}
}
//举例2
class order{
public void method(Object obj){
}
}
多态性是一种运行时行为

向下转型
如果使用多态new一个对象,那么这个对象并不能调用子类中的特有方法,但是如果想调用子类中的特有方法,可通过”向下转型(使用强制类型转换符)“,当然使用强转时可能会出现异常(ClassCastException异常)。
people p = new student();//此时p不能调用student的特有方法
student s = (student)p;//通过向下转型,s可以调用student的特有方法
如果想要向下转型成功,则new的必须为其子类
//情况1
person p = new person();
man m = (man)p; //报错
//情况2
object p = new man();
person m =(person)p; //正常运行,man为person的子类,强转为man可以,则强转为person也可以
//情况3
person p = new woman();
man m = (man)p; //报错
//情况4 直接"="
man p = new woman(); //报错
//只有两者类型相等或者是其子类的情况下才能直接用"="
instanceof关键字
a instanceof A //判断对象a的运行类型是否是类A或其子类,如果是返回true,如果不是返回false
使用情境:为了避免在向下转型时出现“ClassCastException“异常,在进行向下转型之前先用instanceof进行判断,如果为true才向下转型。
people p = new man();
if(p instanceof man){ //p instanceof man结果为true
man m = (man)p; //进行转型
}