好好学Java:从零基础到项目实战
上QQ阅读APP看书,第一时间看更新

2.1.3 强制类型转换

在编码过程中,不但能将数字赋值给某个变量,还能将一个变量赋值给另一个变量。比如下面的代码把整型变量changjiang赋值给整型变量longRiver(完整代码见本章源码的src\com\arithmetic\ numerical\Convert.java):

        int changjiang=6397;  // 长江的长度为6397千米
        System.out.println("changjiang="+changjiang);
        int longRiver=changjiang;  // 把一个整型变量赋值给另一个整型变量
        System.out.println("longRiver="+longRiver);

运行上面的测试代码,从下面的输出日志可以发现两个整型变量的数值一模一样。

changjiang=6397

longRiver=6397

同类型的变量之间互相赋值完全没有问题,麻烦的是给不同类型的变量赋值。如果是把整型变量赋值给长整型变量,编译器睁一只眼闭一只眼就给放行了;如果是把长整型变量赋值给整型变量, IDEA就会直接提示错误Incompatible types。比如以下代码就会报错:

        long changjiang=6397;  // 长江的长度为6397千米
        // 若把长整型变量直接赋值给整型变量,编译器会提示错误
        int longRiver=changjiang;  // 把长整型变量赋值给整型变量,注意编译器会报错

此时需要在原变量前面添加“(新类型)”表示强制将该变量转换为新类型。改写后的变量赋值语句就变成了下面这样:

        long changjiang=6397;  // 长江的长度为6397千米
        // 不同类型的变量相互赋值,需要在原变量前面添加“(新类型)”表示强制转换类型
        int longRiver=(int) changjiang;  // 把长整型数强制转换成整型数

然而,不同类型的变量相互赋值是有风险的,尤其是把高精度的数字赋值给低精度的数字,例如将8字节的长整型数强制转换成4字节的整型数,结果只有低位的4字节保留了下来,而高位的4字节被舍弃掉了。下面做一个实验,先用长整型变量保存世界人口的数量74亿,再把该长整型变量赋值给整型变量,具体代码如下:

        long worldPopulation=7444443881L; //截至2018年元旦,世界人口大约有74亿
        System.out.println("worldPopulation="+worldPopulation);
        // 把长整型数赋值给整型数会丢失前4字节
        int shijierenkou=(int) worldPopulation;  // 把长整型数强制转换成整型数
        System.out.println("shijierenkou="+shijierenkou);

运行以上的实验代码,打印出来的变量值见以下日志:

worldPopulation=7444443881

shijierenkou=-1145490711

可见将超大的长整型数强制转换成整型数,结果整个数值都变了。

既然整数之间强制转换类型存在问题,小数之间强制转换类型也不例外。倘若把双精度数强制转换成浮点数,数字精度也会变差。接下来,仍然通过实验观察,以常见的圆周率为例,它的密率是中国古代数学家祖冲之发现的,其数值约为3.1415926,包括小数部分在内共有8位数字。由于double类型的数字精度达到15~16位,因此利用双精度变量保存圆周密率完全没有问题。但是如果将这个密率的双精度变量赋值给浮点变量,会发生什么情况呢?下面的代码将演示把双精度数强制转换成浮点数的场景:

        // 3.1415926是中国古代数学家祖冲之求得的圆周率数值,又称祖率
        double zulv=3.1415926;
        System.out.println("zulv="+zulv);
        // 把双精度数赋值给浮点数会丢失数值精度
        float pai=(float) zulv;  // 把双精度数强制转换成浮点数
        System.out.println("pai="+pai);

运行上述实验代码,日志打印的变量值如下:

zulv=3.1415926

pai=3.1415925

可见浮点变量保存的密率数值变成了3.1415925,与双精度变量相比,末尾的6变为5了。之所以密率数值发生变化,是因为float类型的数字精度只有6~7位,而前述密率的总位数达到8位,显然超出了float类型的精度范围,使得强转之后的浮点变量损失了范围外的精度。

除了整数之间互转、小数之间互转以外,还有整数转小数和小数转整数的情况,不过整数与小数互转依然存在数值亏损的问题。譬如,一个双精度变量赋值给一个整型变量,由于整型变量没有空间保存小数部分,因此原本双精度变量在小数点后面的数字全被舍弃。以下代码将示范这种数字类型转换:

        double jiage=9.9;  // 某商品定价为9.9元
        System.out.println("jiage="+jiage);
        // 把小数赋值给整型变量,会直接去掉小数点后面的部分,不会四舍五入
        int price=(int) jiage;  // 把双精度数强制转换成整型数
        System.out.println("price="+price);

运行以上的测试代码,日志打印结果如下:

jiage=9.9

price=9

果然整型变量丢掉了双精度变量的小数部分。由此可见,不同类型之间的变量互转问题多多,若非必要,一般不要强制转换两个变量的数值类型。