单分派、多分派

来源:互联网 发布:玫瑰香水 知乎 编辑:程序博客网 时间:2024/05/16 12:17

单分派、多分派

http://blog.csdn.net/fan2012huan/article/details/51004615

方法的接收者和方法的参数统称为方法的宗量。 根据分派基于宗量多少(接收者是一个宗量,参数是一个宗量),可以将分派分为单分派和多分派。单分派是指根据一个宗量就可以知道调用目标(即应该调用哪个方法),多分派需要根据多个宗量才能确定调用目标。
请看示例:

/** * Created by fan on 2016/3/29. */public class Dispatcher {    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());    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

执行结果如下所示:
这里写图片描述
字节码指令如下所示:

public static void main(java.lang.String[]);  Code:   Stack=3, Locals=3, Args_size=1   0:   new     #2; //class Dispatcher$Father   3:   dup   4:   invokespecial   #3; //Method Dispatcher$Father."<init>":()V   7:   astore_1   8:   new     #4; //class Dispatcher$Son   11:  dup   12:  invokespecial   #5; //Method Dispatcher$Son."<init>":()V   15:  astore_2   16:  aload_1   17:  new     #6; //class Dispatcher$_360   20:  dup   21:  invokespecial   #7; //Method Dispatcher$_360."<init>":()V   24:  invokevirtual   #8; //Method Dispatcher$Father.hardChoice:(LDispatcher$_360;)V   27:  aload_2   28:  new     #9; //class Dispatcher$QQ   31:  dup   32:  invokespecial   #10; //Method Dispatcher$QQ."<init>":()V   35:  invokevirtual   #11; //Method Dispatcher$Father.hardChoice:(LDispatcher$QQ;)V   38:  return
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

从上面的字节码指令中可以看到,两次方法调用

        father.hardChoice(new _360());        son.hardChoice(new QQ());
  • 1
  • 2
  • 1
  • 2

对应的字节码指令都是一样的,只是参数不同而已:

   24:  invokevirtual   #8; //Method Dispatcher$Father.hardChoice:(LDispatcher$_360;)V   35:  invokevirtual   #11; //Method Dispatcher$Father.hardChoice:(LDispatcher$QQ;)V
  • 1
  • 2
  • 1
  • 2

由此可见,在class文件中都是调用Father的hardChoice()方法。

解析

在java源代码进行编译的过程中,发生了这么个事情。
首先确定方法的接收者,发现两个对象变量的静态类型都是Father类型的,因此在class文件中写的Father类中方法的符号引用。
再者,对于方法参数,一个是_360对象,一个是QQ对象,按照静态类型匹配的原则,自然找到各自的方法。
上面的两步都是在编译器中做出的,属于静态分派,在选择目标方法时根据了两个宗量,是多分派的。因此,静态分派属于多分派类型。
当java执行时,当执行到son.hardChoice(new QQ()); 时,发现son的实际类型是Son,因此会调用Son类中的方法。在执行father.hardChoice(new _360()); 时也有这个过程,只不过father的实际类型就是Father而已。发现,在目标选择时只依据了一个宗量,是单分派的。因此,动态分派属于单分派类型。

0 0