博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
静态分派和动态分派
阅读量:3982 次
发布时间:2019-05-24

本文共 2599 字,大约阅读时间需要 8 分钟。

首先是两个概念:

  • 静态类型,即是变量声明时的类型
  • 实际类型,变量实例化时采用的类型

比如我们有这样一段代码

class Human {}public class Man extends Human {    public static void main(String[] args) {        Human man = new Man();    }}

我们就称变量 man 的静态类型为 Human,实际类型为 Man。

静态分派

编译期所有依赖静态类型来定位方法执行版本的分派动作称为静态分派,其典型应用是方法重载(根据参数的静态类型来定位目标方法)。

静态分派发生在编译阶段,因此确定静态分派的动作实际上不是由虚拟机执行的。静态类型在编译期是可知的;

动态分派

运行期根据实际类型确定方法执行版本的分派动作称为动态分派,其典型应用是方法重写

本文以Java多态的一些基本特征来谈一下分派调用。

在开始,依旧用常用方式,例子来引入,看一看下面例子的输出:

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
37
38
39
40
41
42
43
44
45
46
47
48
/**
 
*
 
* @author Sel
 
*
 
* 2014.4.3
 
*/
public
class
StaticDispatch {
 
     
    
public
void
sayHello(Human guy) {
        
System.out.println(
"hello, guy!"
);
    
}
     
    
public
void
sayHello(Man guy) {
        
System.out.println(
"hello, man!"
);
    
}
     
    
public
void
sayHello(Women guy) {
        
System.out.println(
"hello, women!"
);
    
}
     
    
public
static
void
main(String[] args) {
         
        
Human man =
new
Man();
         
        
Human women =
new
Women();
         
        
StaticDispatch sd =
new
StaticDispatch();
         
        
sd.sayHello(man);
         
        
sd.sayHello(women);
 
    
}
 
}
 
class
Human {
     
}
 
class
Man
extends
Human {
     
}
 
class
Women
extends
Human {
     
}
输出结果:

hello, guy!
hello, guy!

没错,程序就是大家熟悉的重载(Overload),而且大家也应该能知道输出结果,但是为什么输出结果会是这个呢?

先来谈一下以下代码的定义:

1
Human man =
new
Man();

我们把 
Human
称为变量的 
静态类型
, 
Man
称为变量的 
实际类型

其中,变量的静态类型和动态类型在程序中都可以发生变化,而区别是变量的静态类型是在编译阶段就可知的,但是动态类型要在运行期才可以确定,编译器在编译的时候并不知道变量的实际类型是什么(个人认为可能也是因为要实现多态,所以才会这样设定)。

现在回到代码中,由于方法的接受者已经确定是StaticDispatch的实例sd了,所以最终调用的是哪个重载版本也就取决于传入参数的类型了。

实际上,虚拟机(应该说是编译器)在重载时时通过参数的静态类型来当判定依据的,而且静态类型在编译期可知,所以编译器在编译阶段就可根据静态类型来判定究竟使用哪个重载版本。于是对于例子中的两个方法的调用都是以Human为参数的版本。

Java中,所有以静态类型来定位方法执行版本的分派动作,都称为静态分派


再来看动态分派,它和多态的另外一个重要体现有很大的关联,这个体现是什么,可能大家也能猜出,没错,就是重写(override)。

例子如下:

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
37
38
39
40
41
42
43
44
/**
 
*
 
* @author Sel
 
*
 
* 2014.4.3
 
*/
public
class
DynamicDispatch {
 
    
public
static
void
main(String[] args) {
         
        
Human man =
new
Man();
        
Human women =
new
Women();
         
        
man.sayHello();
        
women.sayHello();
         
        
man =
new
Women();
        
man.sayHello();
 
    
}
 
}
 
abstract
class
Human {
    
protected
abstract
void
sayHello();
}
 
class
Man
extends
Human {
 
    
@Override
    
protected
void
sayHello() {
        
System.out.println(
"hello man!"
);
    
}
     
}
 
class
Women
extends
Human {
 
    
@Override
    
protected
void
sayHello() {
        
System.out.println(
"hello women!"
);
    
}
     
}


输出结果:

hello man!
hello women!
hello women!


这个结果已经没什么好说的了,而虚拟机是如何知道要调用哪个方法的呢?

其实由两次改变man变量的实际类型导致调用函数版本不同,我们就可以知道,虚拟机是根据变量的实际类型来调用重写方法的。

我们也可以从例子中看出,变量的实际类型是在运行期确定的,重写方法的调用也是根据实际类型来调用的。

我们把这种在运行期根据实际类型来确定方法执行版本的分派动作,称为动态分派

单分派和多分派

单分派:根据一个宗量对目标方法进行选择。动态分派属于单分派

多分派:根据多余一个宗量对目标方法进行选择。静态分派属于多分派

转载地址:http://lzpui.baihongyu.com/

你可能感兴趣的文章
coursesa课程 Python 3 programming course_2_assessment_7 多参数函数练习题
查看>>
coursesa课程 Python 3 programming 排序函数sorted的可选参数
查看>>
coursesa课程 Python 3 programming course_2_assessment_8 sorted练习题
查看>>
visca接口转RS-232C接口线序
查看>>
在unity中建立最小的shader(Minimal Shader)
查看>>
RGB 立方体
查看>>
1.3 Debugging of Shaders (调试着色器)
查看>>
关于phpcms中模块_tag.class.php中的pc_tag()方法的含义
查看>>
vsftp 配置具有匿名登录也有系统用户登录,系统用户有管理权限,匿名只有下载权限。
查看>>
linux安装usb wifi接收器
查看>>
关于共享单车定位不准问题
查看>>
ubuntu误删文件造成软件包信息列表损坏无法更新或安装文件
查看>>
终于搞定CString和string之间转换的问题了
查看>>
用防火墙自动拦截攻击IP
查看>>
补充自动屏蔽攻击ip
查看>>
多字节与UTF-8、Unicode之间的转换
查看>>
通信和通讯有什么区别?
查看>>
谷歌走了
查看>>
多线程使用随机函数需要注意的一点
查看>>
getpeername,getsockname
查看>>