方法的接收者和方法的参数统称为方法的宗量。 根据分派基于宗量多少(接收者是一个宗量,参数是一个宗量),可以将分派分为单分派和多分派。单分派是指根据一个宗量就可以知道调用目标(即应该调用哪个方法),多分派需要根据多个宗量才能确定调用目标。
如下代码:
package diptch;
public class DynamicDispatch {
static class QQ {}
static class _360 {}
public static class Father {
public void hardChoice(QQ arg) {
System.out.println("father choose QQ");
}
public void hardChoice(_360 arg) {
System.out.println("father choose _360");
}
}
public static class Son extends Father {
@Override
public void hardChoice(QQ arg) {
System.out.println("son choose QQ");
}
@Override
public void hardChoice(_360 arg) {
System.out.println("son choose 360");
}
}
public static void main(String[] args) {
Father father = new Father();
Father son = new Son();
father.hardChoice(new _360());
son.hardChoice(new QQ());
}
}
执行结果:
father choose _360
son choose QQ
来看字节码字节码指令具体执行:
public static void main(java.lang.String[]);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=3, args_size=1
0: new #16 // class diptch/DynamicDispatch$Fa
ther
3: dup
4: invokespecial #18 // Method diptch/DynamicDispatch$F
ather."<init>":()V
7: astore_1
8: new #19 // class diptch/DynamicDispatch$So
n
11: dup
12: invokespecial #21 // Method diptch/DynamicDispatch$S
on."<init>":()V
15: astore_2
16: aload_1
17: new #22 // class diptch/DynamicDispatch$_3
60
20: dup
21: invokespecial #24 // Method diptch/DynamicDispatch$_
360."<init>":()V
24: invokevirtual #25 // Method diptch/DynamicDispatch$F
ather.hardChoice:(Ldiptch/DynamicDispatch$_360;)V
27: aload_2
28: new #29 // class diptch/DynamicDispatch$QQ
31: dup
32: invokespecial #31 // Method diptch/DynamicDispatch$Q
Q."<init>":()V
35: invokevirtual #32 // Method diptch/DynamicDispatch$F
ather.hardChoice:(Ldiptch/DynamicDispatch$QQ;)V
38: return
LineNumberTable:
line 31: 0
line 32: 8
line 33: 16
line 34: 27
line 35: 38
LocalVariableTable:
Start Length Slot Name Signature
0 39 0 args [Ljava/lang/String;
8 31 1 father Ldiptch/DynamicDispatch$Father;
16 23 2 son Ldiptch/DynamicDispatch$Father;
}
C:\Users\Administrator\js>
首先确定方法的接收者,发现两个对象变量的静态类型都是Father类型的,因此在class文件中写的Father类中方法的符号引用如下。
24: invokevirtual #25 //Methoddiptch/DynamicDispatch$Father.hardChoice(Ldiptch/DynamicDpatch$_360;)V
35: invokevirtual #32 // Method diptch/DynamicDispatch$F
ather.hardChoice:(Ldiptch/DynamicDispatch$QQ;)V
两个方法的接受者都是Father 这个静态类型,形参部分的具体类型也是在编译器就已经确定了静态类型,然后各自找各自的方法所以静态类型属于多分派
然后在看son.hardChoice(new QQ());这个方法 son的静态类型是Father,实际类型是Son,准确的说是在执行invokevirtual 这个字节码指令时,他只会关心你的实际类型,而不会去操心你的参数,因为这时候方法形参不管是实际类型,还是静态类型都不会对方法的选择有任何影响。