java多态 运行时多态和编译时多态
我们知道java的多态是一个重要的特性,其中体现java的多态有两种形式。运行时的多态和编译时的多态。
编译时的多态会发生在方法重载的时候,方法的重载指方法名相同,方法的参数列表不同,这样在类加载的
时候就会加载两个方法的版本。这个过程是在编译期就是确定的,这时候我们通过不同参数调用相同函数名的
时候就会有不同的结果,这是编译时的多态,需要注意的加载函数版本不同是根据参数列表确定的,而不是根据方
法返回值类型确定的,也就是说方法参数列表不同才会有重载。调用不同版本函数的时候才会有不同的结果
运行时的多态发生在继承的时候,父类有个方法,子类重写(覆盖)了父类的方法。父类有一个函数,子类定义了一个
和父类相同的函数,包括参数列表相同。这时候由父类对象指向子类的实例的时候,就会调用子类的方法。这是运行
时多态的典型例子。下面我们也会给出具体的代码来让我们更深入的了解继承之后的运行时多态。
package MM;
public class TestPolymorphic {
static class A {
public void print(A a) {
System.out.println("A and a");
}
public void print(D d) {
System.out.println("A and D");
}
}
static class B extends A{
public void print(A a) {
System.out.println("B and A");
}
public void print(B b) {
System.out.println("B and b");
}
}
static class C extends B{
}
static class D extends B{
}
public static void main(String[] args) {
A a1=new A();
A a2=new B();
B b=new B();
C c=new C();
D d=new D();
a1.print(b);
a1.print(c);
a1.print(d);
a2.print(b);
a2.print(c);
a2.print(d);
b.print(b);
b.print(c);
b.print(d);
}
}
我们来分析下上面的结果。根据对象的不同我们分成三份来分析
首先声明的A的对象 A a1=new A();这时候传入对象的时候,如果该方法的参数是对应的类
的对象则会执行对应的方法,如果没有,就会用父类对象来代替子类对象进入方法。因为父类对象即子类对象。
所以输出的结果会出现最上面的三条。
然后声明了父类的变量指向了子类对象,A a2=new B();这时候体现了多态性,首先执行a2.print(b);这时候子类
是存在参数是b的类print函数,但是父类中不存在,所以会用父类对象代替子类对象传入参数,调用父类中的
public void print(A a)这时候发现子类中重写了这个方法,所以会调用子类的public void print(A a)方法。所以
会输出第四条语句。第五条也同理输出B and A。第六条中父类有参数为D类对象的print方法,所以会输出A and D
最后声明了子类变量指向子类对象的实例,B b=new B();这时候调用子类的函数的如果子类有对应的函数则会直接
如果子类没有对应的函数,而父类有,会调用父类的函数,如果子类和父类都没有,会把参数的父类对象传给调用的
函数,然后再按照子类父类的顺序查看是否有对应的函数。
需要注意的是:多态性体现在父类的变量指向子类变量。当我们用父类变量指向子类变量的时候,这个父类变量没
办法调用子类中写了的而父类中没写的方法。这也是后两种对象的调用函数的区别。