![Java无难事:详解Java编程核心思想与技术(第2版)](https://wfqqreader-1252317822.image.myqcloud.com/cover/851/47548851/b_47548851.jpg)
2.4 类型转换的奥秘
先看一个例子,代码2.3如下:
代码2.3 TypeConverting.java
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_46_2.jpg?sign=1739527940-vVafFK26H6ke0372eCrgsWmwpHihR4gI-0-b630eb0027b92c3b65a87b5cef2d00c3)
当我们编译这个类时,编译器会报告一个错误:
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_46_3.jpg?sign=1739527940-bWKxJHa5zOPQrvcZoElZ0xpu48UYTA4Q-0-38c0b13fea515ccdd4f8b96fae794d5c)
编译器告诉我们类型不兼容,无法把int类型转换为byte类型,而且编译器还告诉我们问题出在了TypeConverting.java的第4行,即下面的代码:
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_46_4.jpg?sign=1739527940-9oYiq0b2fPNuUlt5EaegfyuJAUNIrbcy-0-01b04821dfa9c28ee7190548d37b34d4)
变量b是byte类型,数值3也没有超出byte类型的存储范围,那么为什么会出现“不兼容的类型:从int转换到byte可能会有损失”这样的错误呢?第一感觉应该是数值3被编译器认为是一个int类型的整数字面常量,那么我们把数值3强行转换为byte类型应该就可以了,强制类型转换的语法是在变量前加上“(变量类型)”,修改第4行的代码:
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_46_5.jpg?sign=1739527940-pUcL0ImONXMtmqsoaL7kXcLxnV3CwBi1-0-c73e537145c82ce6f782c98947fac8ff)
再次编译,结果还是出现了上述错误,看来问题不是出在数值3上,那么应该是“b*3”的结果是int类型,也就是说,虽然计算结果是9,并未超出byte类型的表数范围,但该结果被自动数据类型提升为了int类型,所以导致出现类型不兼容的问题。下面把第4行改为:
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_46_6.jpg?sign=1739527940-zcMYr2sr2nhkUCN6S4puVMO94rbWF5XM-0-4632369704c7e9d63d530df1b19bc7d5)
现在,编译通过了。有些读者可能会问:为什么要在“b*3”外面加上一个圆括号呢?在Java中,类型转换运算的优先级比乘法运算符的优先级要高,所以要转换“b*3”的计算结果的类型,应该在“b*3”外面加上括号,否则就是转换b为byte类型了。
现在,我们已经了解了如何进行类型转换,但是上面例子的类型转换还是比较正常的,下面我们来看一个会出现问题的例子,如代码2.4所示。
代码2.4 Overflow.java
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_47_1.jpg?sign=1739527940-hIQNFPl8jC2RTzZ4GhD155ZakOrIeKRb-0-547454878dbed23aa74eb99337ac4514)
程序的运行结果为:
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_47_2.jpg?sign=1739527940-sYgFg1WCUEo3i4a0KzZGkNQjIYGc9ulm-0-05a24c51a91b86a8de46a3a597131f95)
我们发现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)。
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_47_3.jpg?sign=1739527940-vcx8L22z7PG71sNsOL35zg6atBL51QMn-0-2b934b6e4f3931be21ab1735fed861c7)
注意:在我们使用类型转换时,要注意溢出这种情况,尤其是当占用字节数较多的类型转换为占用字节数较少的类型时,一定要注意是否会出现溢出的情况。
下面我们来看看把浮点数转换成整数的情况,如代码2.5所示。
代码2.5 Float2Int.java
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_47_4.jpg?sign=1739527940-hkts9seGpCzaiPbDE5m9CvHcFGDUhUbA-0-4c884dbb6dbbd3a4b11aa457256be340)
程序的运行结果为:
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_47_5.jpg?sign=1739527940-OvXKvZs99PF4sJA38ZGVaAMoH23NvSGA-0-804285a33e28f73a743397ded426e7ad)
从结果可以看出,Java直接把浮点数小数点后面的值抛弃,保留整数部分。那么在浮点数转换为整数时,会不会四舍五入呢?答案是不会,读者可以把3.1415926改为3.9试试。
那么int是否可以转换成boolean类型呢?很不幸,Java不允许这么做。
代码2.6 Num2Bool.java
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_48_1.jpg?sign=1739527940-JbMPRP93cUdmjO9PY1zpNiVsJcKLXraA-0-fc74ba35c2d2b35c47c986a55d791f7b)
当用javac编译上面的程序时,编译器会提示“错误:不兼容的类型:int无法转换为boolean”。也就是说,并不是任何类型之间都能相互转换的。
要注意的是,在Java中并没有提供地址访问功能,所以不能像C++那样使用指针随意地进行强制类型转换,Java中的强制类型转换,不仅要考虑数据的内存布局是否兼容,还要考虑数据本身是否兼容。比如上例的boolean类型,虽然它只占用1个字节,在理论上和整型数据可以互相转换,但该类型的数据只用于逻辑运算(只有两个值:true和false),Java编译器强制保证boolean类型和其他类型之间无法通过类型转换来互相使用,这有助于我们编写健壮和安全的程序。