- Java无难事:详解Java编程核心思想与技术
- 孙鑫
- 1264字
- 2021-01-05 17:31:19
2.4 类型转换的奥秘

扫码看视频
先看一个例子,代码2.3如下:

当我们编译这个类时,编译器会报告一个错误:

编译器告诉我们类型不兼容,无法把int类型转换为byte类型,而且编译器还告诉我们问题出在了TypeConverting.java 的第4行,即下面的代码:

变量b是byte类型,数值3也没有超出byte类型的存储范围,那么为什么会出现“不兼容的类型:从int转换到byte可能会有损失”这样的错误呢?第一感觉应该是数值3被编译器认为是一个int类型的整数字面常量,那么我们把数值3强行转换为byte类型应该就可以了,强制类型转换的语法是在变量前加上“(变量类型)”,修改第4行的代码:

再次编译,结果还是出现了上述错误,看来问题不是出在数值3上,那么应该是“b * 3”的结果是int类型,也就是说,虽然计算结果是9,并未超出byte类型的表数范围,但该结果被自动数据类型提升为了int类型,所以导致出现类型不兼容的问题。下面把第4行改为:

现在,编译通过了。有些读者可能会问:为什么要在“b * 3”外面加上一个圆括号呢?在Java中,类型转换运算的优先级比乘法运算符的优先级要高,所以要转换“b * 3”的计算结果的类型,应该在“b * 3”外面加上括号,否则就是转换b为byte类型了。
现在,我们已经了解了如何进行类型转换,但是上面例子的类型转换还是比较正常的,下面我们来看一个会出现问题的例子,如代码2.4所示。

程序的运行结果为:

我们发现4194303变为了-1。虽然编译器没有报告类型错误,但是程序的执行结果并不能让我们接受。在2.2.1节中,我们已经知道short类型占用2个字节,int类型占用4个字节。在上面的例子中,0x3FFFFF这个十六进制数占用了3个字节,当我们使用int类型变量存储时没有任何问题,但是当我们转换为short类型时,就会出现多出1个字节无处存放的问题,这就是类型转换时的溢出。
当我们使用类型转换时,多出来的一个字节会被直接抛弃。那么Java是抛弃最前面的3F,还是抛弃最后面的FF呢?从a变量的结果来看,Java抛弃的是前面的3F(a变量的值在16进制下是0xFFFF,转换为10进制则是-1)。

注意:在我们使用类型转换时,要注意溢出这种情况,尤其是当占用字节数较多的类型转换为占用字节数较少的类型时,一定要注意是否会出现溢出的情况。
下面我们来看看把浮点数转换成整数的情况,如代码2.5所示。

程序的运行结果为:

从结果可以看出,Java直接把浮点数小数点后面的值抛弃,保留整数部分。那么在浮点数转换为整数时,会不会四舍五入呢?答案是不会,读者可以把3.1415926改为3.9试试。
那么int是否可以转换成boolean类型呢?很不幸,Java不允许这么做。

当用javac编译上面的程序时,编译器会提示“错误: 不兼容的类型: int无法转换为boolean”。也就是说,并不是任何类型之间都能相互转换的。
要注意的是,在Java中并没有提供地址访问功能,所以不能像C++那样使用指针随意地进行强制类型转换,Java中的强制类型转换,不仅要考虑数据的内存布局是否兼容,还要考虑数据本身是否兼容。比如上例的boolean类型,虽然它只占用1个字节,在理论上和整型数据可以互相转换,但该类型的数据只用于逻辑运算(只有两个值:true和false),Java编译器强制保证boolean类型和其他类型之间无法通过类型转换来互相使用,这有助于我们编写健壮和安全的程序。