多态
多态在程序中的体现:父类的引用或者接口的引用指向了子类的对象。
多态的好处:提高了代码的扩展性。
多态的弊端:不能使用子类的特有方法。
多态的前提:
- 必须有关系,继承,实现。
- 通常有覆盖。
多态--向上转型
//Animal 抽象类
package demo;
abstract class Animal {
abstract void eat();
}
//Dog子类
package demo;
public class Dog extends Animal{
@Override
void eat() {
System.out.print("骨头");
}
void sleep() {
System.out.print("sleep");
}
}
//向上转型
Animal a=new Dog();
a.eat();
//注意a面对的是父类型,不能调用子类特有的sleep方法
向上转型的好处:隐藏了子类型,提高了扩展性。
向上转型的弊端:只能使用父类中的功能,不能使用子类特有功能。功能被限定了。
如果不需要面对子类型,同时提高扩展性或者使用父类的功能即可完成操作,就使用向上转型。
如果子类中重写了父类中的一个方法,那么在调用这个方法的时候,将会调用子类中的这个方法
多态--向下转型
//Animal 抽象类
package demo;
abstract class Animal {
abstract void eat();
}
//Dog子类
package demo;
public class Dog extends Animal{
@Override
void eat() {
System.out.print("骨头");
}
void sleep() {
System.out.print("sleep");
}
}
//先向上转型
Animal a=new Dog();
//再向下转型
//判断一个对象是否匹配某一个类型,简单说就是一个对象是否是特定类的一个实例
if(a instanceof Dog){
Dog d=(Dog)a;
d.eat();
d.sleep();
}else{
System.out.print("类型不匹配");
}
向下转型的好处:可以使用子类型的特有功能。
向下转型的弊端:面对具体的子类型,向下转型有风险。容易发生ClassCastException,只要转换类型和对象类型不匹配就会发生。想要安全,必须要进行判断。判断一个对象是否匹配某一个类型,需要使用一个关键字instanceof。
什么时候用向下转型:需要子类型的特有方法时。但一定要判断。
多态中成员变量的调用
当子父类中出现同名成员变量时,多态调用时,只看调用该成员变量的引用所属的类中的成员变量。
简单说:无论编译或者运行,都看等号的左边。
//父类
class Fu{
int num=4;
}
//子类
class Zi extends Fu{
int num=6;
}
//
Fu f=new Zi();
System.out.print(f.num);
//输出结果为父类的4
多态中成员函数的调用
出现一模一样函数时多态调用,编译时,看的是引用变量所属的类中的方法,运行时,看的是对象所属的类中的方法。
简单说就是编译看左边,运行右边。
成员方法动态绑定到当前对象上。
下面多态调用函数代码中:编译看左边,运行看右边。运行时如果子类有和父类一模一样的函数时,调用的是子类(覆盖),如果子类没有,则调用父类函数。如何父类没有,编译会报错。
//父类
class Fu{
void show(){
System.out.print("父show");
}
}
//子类
class Zi extends Fu{
void show(){
System.out.print("子show");
}
}
//
Fu f=new Zi();
f.show();
//输出结果为子show
多态中静态函数
出现一模一样函数时,多态调用,编译和运行是看引用变量所属的类中的方法。
简单说就是:编译和运行看左边。
其实真正调用静态方法是不需要对象的。直接类名调用。因为静态方法绑定到类上。所以下面情况,更多用于面试。
//父类
class Fu{
static void show(){
System.out.print("父show");
}
}
//子类
class Zi extends Fu{
static void show(){
System.out.print("子show");
}
}
//
Fu f=new Fu();
f.show();
Zi b=(Zi)f;
b.show();
//输出结果为第一个父show,第二个子show