多态是继封装、继承之后,面向对象的第三大特性。
生活中,比如跑的动作,小猫、小狗和大象,跑起来是不一样的。再比如飞的动作,昆虫、鸟类和飞机,飞起来也是不一样的。可见,同一行为,通过不同的事物,可以体现出来的不同的形态。多态,描述的就是这样的状态。
多态 (多种形态) 是同一个行为具有多个不同表现形式或形态的能力,多态就是同一个接口,使用不同的实例而执行不同操作
父类类型 变量名 = new 子类对象;
变量名.方法名();
父类类型:指子类对象继承的父类类型,或者实现的父接口类型。
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的重写方法。
使用多态的好处是,可以使程序有良好的扩展,并可以对所有类的对象进行通用处理
实际开发的过程中,父类类型作为方法形式参数,传递子类对象给方法,进行方法的调用,更能体现出多态的扩展性与便利。
public class Animal {
public void run(){
System.out.println("动物跑起来......");
}
}
class Cat extends Animal{
@Override
public void run(){
System.out.println("猫跑起来.....");
}
public void catchMouse(){
System.out.println("抓老鼠......");
}
}
class Dog extends Animal{
@Override
public void run(){
System.out.println("狗狗跑起来......");
}
public void keepDoor(){
System.out.println("看门........");
}
}
public class Demo_Polymorphic {
public static void show(Animal a){
//会根据传入的参数的不同,调用不同的子类重写的方法,体现了多态的特征
a.eat();//分别调用子类的重写,体现了多态的特征
}
public static void main(String[] args){
show(new Animal());
show(new Cat());//以Cat为对象调用show方法;
show(new Dog());//以Dog为对象调用show方法;
}
}
父子对象之间的转换分为了向上转型和向下转型 , 它们区别如下:
向上转型: 通过子类对象 (小范围) 实例化父类对象 (大范围),这种属于自动转换
注意: 其意义在于当我们需要多个同父的对象调用某个方法时,通过向上转换后,则可以确定参数的统一。方便程序设计
对象的向上转型(安全的):会失去子类新增。 子类对象,被看做了父类的类型。那么就不能访问子类的新增, 只能访问父类的属性和方法。以及子类重写。
/**
* 向上转型案例
*/
public class HelloUp {
public static void main(String args[]) {
// 通过子类去实例化父类
A a = new B();
a.print();
}
}
class A {
public void print() {
System.out.println("A:print");
}
}
class B extends A {
@Override
public void print() {
System.out.println("B:print");
}
}
向下转型: 通过父类对象 (大范围) 实例化子类对象 (小范围),这种属于强制转换
为什么要转型
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误。也就是说,不能调用子类拥有,而父类没有的方法。
编译都错误,更别说运行了。这也是多态给我们带来的一点"小麻烦"。所以,想要调用子类特有的方法,必须做向下转型。
instanceof关键字
在 Java 中,向下转型则是为了,通过父类强制转换为子类,从而来调用子类独有的方法,为了保证向下转型的顺利完成,在 Java 中提供
了一个关键字 instanceof, 通过 instanceof 可以判断某对象是否是某类的实例,如果是则返回 true, 否则为 false
instanceof:判断某个对象是否是某个类的实例:类以及继承的父类
// 向上转型 (B 是 A 的子类)
A a = new B();
// 返回 true
a instanceof A;
// 返回 true
a instanceof B;
// 返回 false
a instanceof C;
class A{
public void print(){
System.out.println("print:A");
}
}
class B extends A{
@Override
public void print(){
System.out.println("print:B");
}
public void funB(){
System.out.println("funB().....");
}
}
class C extends A{
@Override
public void print(){
System.out.println("print:C");
}
public void funC(){
System.out.println("funC().....");
}
}
父类 对象1 = new 父类();
子类 对象2 = new 子类();
父类 对象3 = new 子类();
结论:
看一个对象能够访问哪些成员,看=左边是定义的是什么类型
父类类型:只能访问父类的属性和方法,
子类类型:可以访问父类的属性和方法,子类新增,子类重写
看一个对象最终访问哪个方法,看=右边是什么类型的对象
父类对象:父类属性和方法
子类对象:父类的属性和方法,以及子类重写的方法