简易Java(04):Java如何进行静态类型检查?

维基百科上对“静态类型检查”和“动态类型检查”的介绍如下:

静态类型检查是一个基于程序源代码分析来确保程序类型安全的过程。

动态类型检查是一个在运行时检查程序类型安全的过程。

Java语言在编译时使用静态类型检查来分析程序。如果有类型错误,则报错。基本思想是不要让类型错误在运行时发生。通过下面的例子,可以更好地理解Java中静态类型检查的工作原理。

1、代码示例

假设我们有如下两个类,AB。并且,B继承A

01 /**
02  * Coder: D瓜哥,http://www.diguage.com/
03  */
04 class A {
05     A me() {
06         return this;
07     }
08  
09     public void doA() {
10         System.out.println("Do A");
11     }
12 }
13  
14 class extends A {
15     public void doB() {
16         System.out.println("Do B");
17     }
18 }

首先,new B().me()返回什么?一个A对象?还是一个B对象?

me()方法确实声明返还一个A对象。所以,在编译的时候,编译器仅仅能看到它返还了一个A对象。但是,在运行时它却返还的是一个B对象,因为B类继承了A类的方法,然后返还了this(自身对象)。

2、静态类型是如何工作的?

下面这行代码是不合法的,即使调用对象确实是B对象。问题就在于它的引用类型是A。在编译时,编译器还不知道它的真实类型,所以这个对象看起来像A.

1 // 非法
2 new B().me().doB();

所以,下面这个方法可以被调用。代码如下:

1 // 合法
2 new B().me().doA();

无论如何,我们可以将类型转换成B,代码如下:

1 // 合法
2 ((B) new B().me()).doB();

如果添加一个C类,代码如下:

1 /**
2  * Coder: D瓜哥,http://www.diguage.com/
3  */
4 class extends A {
5     public void doBad() {
6         System.out.println("Do C");
7     }
8 }

然后,下面这行代码是合法的并且可以通过类型检查。代码如下:

1 // 合法
2 ((C) new B().me()).doBad();

编译器不知道它的真是类型,但是在运行时将会报错一个B不能转换为C的类型转换异常:

1 java.lang.ClassCastException: B cannot be cast to C

D瓜哥注:

“简易Java(01):从HelloWorld中可以学到什么?”中,D瓜哥介绍过Java类加载的过程。方法调用关系会再类加载的链接阶段进行确定。在Java语言中符合“编译期可知,运行时不可变”的方法有静态方法和私有方法两大类,前者与类型直接关联,后者在外部不可被访问,这两种方法的各自特点决定了它们都不可通过继承或者别的方式重写其版本。因此他们都在类加载阶段就确定下来调用版本。

其他方法(除构造器外)则是在运行期根据实际类型确定方法执行版本的。这类方法的分派过程称为动态分派。关于“动态分派”更详细的描述,请看“参考资料”中的《深入理解Java虚拟机》的第八章第8.3.2节“分派”。

《Simple Java》翻译,《简易Java》走起!

参考资料


作 者:  D瓜哥,http://www.diguage.com/
原文链接: http://www.diguage.com/archives/81.html
版权声明:非特殊声明均为本站原创作品,转载时请注明作者和原文链接。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值