![Java无难事:详解Java编程核心思想与技术](https://wfqqreader-1252317822.image.myqcloud.com/cover/59/35011059/b_35011059.jpg)
2.4 类型转换的奥秘
![img](https://epubservercos.yuewen.com/AD1899/18685354708165706/epubprivate/OEBPS/Images/txt002_36.jpg?sign=1739530113-hsTBipq5aasxP8rChjgZgKdT8ZQ8oMSG-0-89eae9e05adeb7c2f6b9f5a99572d9cd)
扫码看视频
先看一个例子,代码2.3如下:
![img](https://epubservercos.yuewen.com/AD1899/18685354708165706/epubprivate/OEBPS/Images/txt002_37.jpg?sign=1739530113-n5iBHD4pACQ5niw8xwOluS5N1XuDjpO3-0-cf52c03b949a548ba7ceb3d8309ae1d3)
当我们编译这个类时,编译器会报告一个错误:
![img](https://epubservercos.yuewen.com/AD1899/18685354708165706/epubprivate/OEBPS/Images/txt002_38.jpg?sign=1739530113-AXok3EVxPkeQZMpKiLVHmfrZsCxVWEDl-0-1e37cca6895d4de4a55b986a78220983)
编译器告诉我们类型不兼容,无法把int类型转换为byte类型,而且编译器还告诉我们问题出在了TypeConverting.java 的第4行,即下面的代码:
![img](https://epubservercos.yuewen.com/AD1899/18685354708165706/epubprivate/OEBPS/Images/txt002_39.jpg?sign=1739530113-6GhL6FFQiyEj1YqhhIjOZTmBvJrucz6o-0-56a1e0672f11934a5b66a7b5d2c1be63)
变量b是byte类型,数值3也没有超出byte类型的存储范围,那么为什么会出现“不兼容的类型:从int转换到byte可能会有损失”这样的错误呢?第一感觉应该是数值3被编译器认为是一个int类型的整数字面常量,那么我们把数值3强行转换为byte类型应该就可以了,强制类型转换的语法是在变量前加上“(变量类型)”,修改第4行的代码:
![img](https://epubservercos.yuewen.com/AD1899/18685354708165706/epubprivate/OEBPS/Images/txt002_40.jpg?sign=1739530113-CaDdBv5oQcRg1BaVItDMEQK1FDZ34L1R-0-f20d3efbc31906ce9ae26a201e7099ec)
再次编译,结果还是出现了上述错误,看来问题不是出在数值3上,那么应该是“b * 3”的结果是int类型,也就是说,虽然计算结果是9,并未超出byte类型的表数范围,但该结果被自动数据类型提升为了int类型,所以导致出现类型不兼容的问题。下面把第4行改为:
![img](https://epubservercos.yuewen.com/AD1899/18685354708165706/epubprivate/OEBPS/Images/txt002_41.jpg?sign=1739530113-H5sDJacf43CksvgE7fDfk5C6yW1PA5dV-0-f627984ee39f161c0e2127b32f5f990a)
现在,编译通过了。有些读者可能会问:为什么要在“b * 3”外面加上一个圆括号呢?在Java中,类型转换运算的优先级比乘法运算符的优先级要高,所以要转换“b * 3”的计算结果的类型,应该在“b * 3”外面加上括号,否则就是转换b为byte类型了。
现在,我们已经了解了如何进行类型转换,但是上面例子的类型转换还是比较正常的,下面我们来看一个会出现问题的例子,如代码2.4所示。
![img](https://epubservercos.yuewen.com/AD1899/18685354708165706/epubprivate/OEBPS/Images/txt002_42.jpg?sign=1739530113-EErtlWMV1w49RMT8ahEcKTk9nP4jNoDJ-0-6a12c53e8f57cdaad0f9a0af25e414f6)
程序的运行结果为:
![img](https://epubservercos.yuewen.com/AD1899/18685354708165706/epubprivate/OEBPS/Images/txt002_43.jpg?sign=1739530113-NhSZ4QR9tq9raLFISuy0QPE2DaHeCzdQ-0-0c1d9733a8944f7cd8272b81431b5518)
我们发现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)。
![img](https://epubservercos.yuewen.com/AD1899/18685354708165706/epubprivate/OEBPS/Images/txt002_44.jpg?sign=1739530113-N84VsLWrMHJsSjSGgs6oClcU7y9FHtcy-0-392d67d7cc19eb1b17fd70a40865c991)
注意:在我们使用类型转换时,要注意溢出这种情况,尤其是当占用字节数较多的类型转换为占用字节数较少的类型时,一定要注意是否会出现溢出的情况。
下面我们来看看把浮点数转换成整数的情况,如代码2.5所示。
![img](https://epubservercos.yuewen.com/AD1899/18685354708165706/epubprivate/OEBPS/Images/txt002_45.jpg?sign=1739530113-qz93OsbmPYt6oj1FpRHB2Kdhn6YRsSD7-0-e72b61cb4123c82819d80075645adc2c)
程序的运行结果为:
![img](https://epubservercos.yuewen.com/AD1899/18685354708165706/epubprivate/OEBPS/Images/txt002_46.jpg?sign=1739530113-YKKqoF2nybCd8GzE90uqrXO1nzxBD9Lf-0-8b7401fe1be50d11e378c1fc04f0b808)
从结果可以看出,Java直接把浮点数小数点后面的值抛弃,保留整数部分。那么在浮点数转换为整数时,会不会四舍五入呢?答案是不会,读者可以把3.1415926改为3.9试试。
那么int是否可以转换成boolean类型呢?很不幸,Java不允许这么做。
![img](https://epubservercos.yuewen.com/AD1899/18685354708165706/epubprivate/OEBPS/Images/txt002_47.jpg?sign=1739530113-nJCq5Mmev1GjKrvUzurBqF0BD9dHXGd3-0-78b8509653c9654ebfbc5517a8169bfe)
当用javac编译上面的程序时,编译器会提示“错误: 不兼容的类型: int无法转换为boolean”。也就是说,并不是任何类型之间都能相互转换的。
要注意的是,在Java中并没有提供地址访问功能,所以不能像C++那样使用指针随意地进行强制类型转换,Java中的强制类型转换,不仅要考虑数据的内存布局是否兼容,还要考虑数据本身是否兼容。比如上例的boolean类型,虽然它只占用1个字节,在理论上和整型数据可以互相转换,但该类型的数据只用于逻辑运算(只有两个值:true和false),Java编译器强制保证boolean类型和其他类型之间无法通过类型转换来互相使用,这有助于我们编写健壮和安全的程序。