一、什么是多态
一个对象变量可以指示多种实际类型。当程序运行时,才能确定该变量引用的哪个类的对象,从而虚拟机自动选择调用哪个方法,这也被称为动态绑定。
二、理解方法的调用过程
我们以x.f(args)为例,A x = new B()。
1.编译器查看对象变量的声明类型和方法名
x声明为A类,编译器将列举A类及其父类中可以被继承的所有名为 f 的方法。由于可能存在重载,名为 f 但参数列表不同的方法可能有多个。
至此编译器获得了所有可能被调用的候选方法。
2.编译器查看调用该方法时提供的参数列表,进行重载解析
如果在候选方法中有与提供的参数列表完全匹配的方法,则选择该方法;
如果没有完全匹配的方法,进行隐式类型转换( 如int可转为double,低精度向高精度转;Son可转为Father,向上转型)可以匹配,则选择该方法。
如果没有一个方法与提供的参数列表匹配,或转型后有多个匹配,都会报错。
至此,编译器获得了需要调用的方法名和参数列表。
3.当程序运行时,动态绑定调用方法。
查找x引用的对象的实际类型,这里为B类。
首先查找x的实际类型B类中有没有具有该参数列表的方法,若有,直接调用该方法。
否则查找其父类A类中查找,以此类推。
为了节约开销,虚拟机预先为每个类创建了一个方法表,只需要查找这个方法表即可。
对于static、private、final方法,可以准确的知道它调用的哪个类,所以采用的是静态绑定。(思考一下为什么)
4.拿段代码感受一下
1 class A {
2 public String show(D obj){
3 return ("A and D");
4 }
5
6 public String show(A obj){
7 return ("A and A");
8 }
9
10 }
11
12 class B extends A{
13 public String show(B obj){
14 return ("B and B");
15 }
16
17 public String show(A obj){
18 return ("B and A");
19 }
20
21 }
22
23 class C extends B{}
24 class D extends B{}
25
26 public class E{
27 public static void main(String [] args){
28 A a1 = new A();
29 A a2 = new B();
30 B b = new B();
31 C c = new C();
32 D d = new D();
33 System.out.println(a1.show(b)); //①
34 System.out.println(a1.show(c)); //②
35 System.out.println(a1.show(d)); //③
36 System.out.println(a2.show(b)); //④
37 System.out.println(a2.show(c)); //⑤
38 System.out.println(a2.show(d)); // ⑥
39 System.out.println(b.show(b)); //⑦
40 System.out.println(b.show(c)); //⑧
41 System.out.println(b.show(d)); //⑨
42 }
43 }

这段代码挺有意思,值得好好体会。在网上看到有的朋友写到,多态的三个条件:继承,重写,父类变量引用子类对象,且多态总伴随着动态绑定。我个人体会这是动态绑定的三个条件,多态也不一定会伴随动态绑定,倒是动态绑定一直伴随着多态。