对象的多态性
java引用变量有两个类型:
一个是编译时的类型,一个是运行时的类型,
编译时的类型由声明该变量时使用的类型决定,
而运行时的类型由实际赋给变量的对象决定。
如果编译时类型和运行时类型不一致,就会出现所谓的多态(ploymorphism)
多态性在面向对象中是一个重要的概念,在java中面向对象主要有一下两种主要体现:
1.方法的重载与覆写。
2.对象的多态性。
对象的多态性主要分为一下两种类型
1、向上转型:子类对象--》父类对象
2、向下转型:父类对象---》子类对象
对于向上转型,程序会自动完成,而对于向下转型时,必须明确致命要转型的子类类型,
【对象转型】
对象向上转型: 父类 父类对象=子类实例;
对象向下转型: 子类 子类对象=(子类)父类实例;
例子:对象向上转型
package test1; class A { public void fun1() { System.out.println("A-->public void fun1(){}"); } public void fun2() { this.fun1(); } } class B extends A { // B继承A类 public void fun1() { // B覆写A的fun1方法 System.out.println("B---> public void fun1(){}"); } public void fun3() { System.out.println("B---> public void fun3(){}"); } } public class PolDemo01 { public static void main(String args[]) { B b = new B(); // 定义子类实现实例化对象 A a = b;// 发生了向上 转型的关系,子类--->父类 a.fun1();// 此类方法被子类覆写过 } }
结果:
B---> public void fun1(){}
以上程序就是一个向上转型的关系,从程序的运行结果中可以发现,此时虽然是使用父类对象调用fun1方法,但实际上调用的方法是被子类覆写过的方法,也就是说,如果对象发生了向上转型关系后,所调用的方法一定是被子类覆写过的方法,但是在此时一定要注意,此时的对象a是无法调用B类中的fun3()方法的,因为此方法只在子类定义,而没有在父类中定义,如果要想调用子类自己的方法,则肯定要使用子类实例,随意此时可以将对象进行向下转型:
范例:对象向下转型
package test2; class A { // 定义父类 public void fun1() { System.out.println("A----> public void fun1(){}"); } public void fun2() { this.fun1(); } } class B extends A { // 子类继承父类 public void fun1() {// 覆写父类的fun1()方法 System.out.println("B-----> public void fun1(){}"); } public void fun3() { System.out.println("B----> public void fun3(){}"); } } public class PolDemo02 { public static void main(String[] args) { A a = new B();// 发生了向上转型的关系,子类---》 父类 B b = (B) a;// 此时发生了向下转型关系 b.fun1();// 调用方法被覆写的方法 b.fun2();// 调用父类的方法 b.fun3();// 调用子类自己定义的方法 } }
结果:
B-----> public void fun1(){}
B-----> public void fun1(){}
B----> public void fun3(){}
如果要想调用子类自己的方法,则一定只能用子类声明对象,另外,在子类中调用了父类中的fun2(),fun2()方法要调用fun1()方法,但此时fun1()方法已经被子类所覆写,所以,此时调用的方法是被子类覆写过的方法。
*************************************************************************************
注意:向下转型的要求
在进行对象的向下转型前,必须首先发生对象向上转型,否则将出现对象转换异常。
**************************************************************************************
下面设计一个方法,要求此方法可以接受A类的任意子类对象,并调用方法。此时,如果不实用对象多态性,则肯定不会使用一下形式的代码:
package test1; class A { public void fun1() { System.out.println("A--->public void fun1(){}"); } public void fun2() { this.fun1(); } } class B extends A { public void fun1() { System.out.println("B---->public void fun1(){}"); } } class C extends A { public void fun1() { System.out.println("C---> public void fun1(){}"); } public void fun5() { System.out.println("C---->public void fun3(){}"); } } public class PolDemo04 { public static void main(String[] args) { fun(new B());// 传递B类实例 fun(new C());// 传递C类实例 } public static void fun(B b) {// 接收子类B的实例 b.fun1();// 统一调用覆写父类的fun1()方法 } public static void fun(C c) {// 接收子类C的实例 c.fun1(); } }
结果:
B---->public void fun1(){}
C---> public void fun1(){}
package test2; class A { public void fun1() { System.out.println("A---> public void fun1(){}"); } public void fun2() { this.fun1(); } } class B extends A { public void fun1() { System.out.println("B--->public void fun1(){}"); } public void fun3() { System.out.println("B--->public void fun3(){}"); } } class C extends A { public void fun1() { System.out.println("C--->public void fun1(){}"); } public void fun5() { System.out.println("C--->public void fun3(){}"); } } public class PolDemo05 { public static void main(String[] args) { fun(new B());// 传递B类实例,产生向上转型 fun(new C());// 传递C类实例,产生向上转型 } public static void fun(A a) {// 接收父类对象 a.fun1(); } }
结果:
B--->public void fun1(){}
C--->public void fun1(){}
在fun()方法中使用了对象的多态性,所以可以接受任何的子类对象,这样无论子类如何增加,fun()方法都不用做任何的改变,
因为一旦发生对象的向上转型关系后,调用的方法一定是被子类覆写过的方法。