3.5 基本类型的类型转换
3.5 基本类型的类型转换
在Java
程序中,不同的基本类型的值经常需要进行相互转换。Java
语言所提供的7种数值类型之间可以相互转换,有两种类型转换方式:自动类型转换和强制类型转换
3.5.1 自动类型转换
Java
所有的数值型变量可以相互转换,如果系统支持把某种基本类型的值直接赋给另一种基本类型的变量,则这种方式被称为自动类型转换。
当把一个表数范围小的数值或变量直接赋给另一个表数范围大的变量时,系统将可以进行自动类型转换;
否则就需要强制转换。
表数范围小的可以向表数范围大的进行自动类型转换,就如同有两瓶水,当把小瓶里的水倒入大瓶中时不会有任何问题。Java
支持自动类型转换的类型如图3.10所示。
1 | char |
图3.10中所示的箭头左边的数值类型可以自动类型转换为箭头右边的数值类型。
程序示例 自动类型转换
下面程序示范了自动类型转换。
1 | public class AutoConversion { |
基本类型转字符串: 连接一个空字符串
不仅如此,当把任何基本类型的值和字符串值进行连接运算时,基本类型的值将自动类型转换为字符串类型,虽然字符串类型不是基本类型,而是引用类型。因此,如果希望把基本类型的值转换为对应的字符串时,可以把基本类型的值和一个空字符串进行连接。
+
不仅可作为加法运算符使用,还可作为字符串连接运算符使用。
程序示例 字符串和数值的连接运算
看如下代码:
1 | public class PrimitiveAndString |
上面程序中有一个“3+4+"Helo!"
”表达式,这个表达式先执行“3+4”运算,这是执行两个整数之间的加法,得到7,然后进行“7+"Helo!"
”运算,此时会把7当成字符串进行处理,从而得到7Helo!
反之,对于“"Helo!"+3+4
”表达式,先进行“"Hell!"+3
”运算,得到一个Hello!3
字符串,再和4进行连接运算,4也被转换成字符串进行处理。
3.5.2 强制类型转换
如果希望把图3.10中箭头右边的类型转换为左边的类型,则必须进行强制类型转换。
强制类型转换的语法格式是:(targetType)value
,强制类型转换的运算符是圆括号()
。当进行强制类型转换时,类似于把一个大瓶子里的水倒入一个小瓶子,如果大瓶子里的水不多还好,但如果大瓶子里的水很多,将会引起溢岀,从而造成数据丢失。
这种转换也被称为“缩小转换(Narrow Conversion
)”。
1 | public class NarrowConversion { |
在上面程序中,把一个浮点数强制类型转换为整数时,Java
将直接截断浮点数的小数部分。除此之外,上面程序还把223强制类型转换为byte
类型的整数,从而变成了23,这就是典型的溢出。图3.11示范了这个转换过程。
从图3.11可以看出,32位int
类型的233在内存中如图3.11上面所示,强制类型转换为8位的byte
类型,则需要截断前面的24位,只保留右边8位,最左边的1是一个符号位,此处表明这是一个负数,负数在计算机里是以补码形式存在的,因此还需要换算成原码。
补码转原码
将补码减1得到反码形式,再将反码取反就可以得到原码。
原码 加权展开 得到十进制
最后的二进制原码为100101,这个byte
类型的值为-(16+4+2+1),也就是-23
从图3.11很容易看出,当试图强制把表数范围大的类型转换为表数范围小的类型时,必须格外小,因为非常容易引起信息丢失。
程序示例 生成随机字符串
经常上网的读者可能会发现有些网页上会包含临时生成的验证字符串,那么这个随机字符串是如何生成的呢?可以先随机生成一个在指定范围内的int
数字(如果希望生成小写字母,就在97~122之间),然后将其强制转换成char
类型,再将多次生成的字符连缀起来即可。
下面程序示范了如何生成一个6位的随机字符串,这个程序中用到了后面的循环控制,不理解循环的读者可以参考后面章节的介绍。
1 | public class RandomStr { |
小数直接量默认是double
下面一行容易出错的代码:
1 | //直接把5.6赋值给f1oat类型变量将出现错误,因为5.6默认是 double类型 |
上面代码中的5.6默认是一个double
类型的浮点数,因此将5.6赋值给一个foat
类型变量将导致错误,必须使用强制类型转换才可以,即将上面代码改为如下形式:
1 | float a = (float) 5.6; |
字符串数字转基本类型数字
在通常情况下,字符串不能直接转换为基本类型,但通过基本类型对应的包装类则可以实现把字符串转换成基本类型。例如,把字符串转换成int
类型,则可通过如下代码实现:
1 | String a ="45"; |
Java
为8种基本类型都提供了对应的包装类,8个包装类都提供了一个parseXxx(String str)
静态方法用于将字符串转换成基本类型。关于包装类的介绍,请参考本书第6章
3.5.3 表达式类型的自动提升
当一个算术表达式中包含多个基本类型的值时,整个算术表达式的数据类型将发生自动提升。Java
定义了如下的自动提升规则:
所有的byte
类型、short
类型和char
类型将被提升到int
类型。
**整个算术表达式的数据类型自动提升到与表达式中最高等级操作数同样的类型**。操作数的等级排列如图3.10所示:
位于箭头右边类型的等级高于位于箭头左边类型的等级。
程序示例
下面程序示范了一个典型的错误:
1 | // 定义一个short类型变量 |
上面的“sValue-2
”表达式的类型将被提升到int
类型,这样就把右边的int
类型值赋给左边的short
类型变量,从而引起错误。
下面代码是表达式类型自动提升的正确示例代码:
1 | byte b = 40; |
整数除法会丢弃小数部分
必须指出,表达式的类型将严格保持和表达式中最高等级操作数相同的类型。下面代码中两个int
类型整数进行除法运算,即使无法除尽,也将得到一个int
类型结果:
1 | int val = 3; |
从上面程序中可以看出,当两个整数进行除法运算时,如果不能整除,得到的结果将是把小数部分截断取整后的整数。
数值和字符串的加法
如果表达式中包含了字符串,则又是另一番情形了。因为当把加号(+)放在字符串和基本类型值之间时,这个加号是一个字符串连接运算符,而不是进行加法运算。看如下代码:
1 | // 输出字符串Hello!a7 |
对于第一个表达式“"Hello!" + 'a' + 7
”,先进行“"Hello!"+a
”运算,把a转换成字符串,拼接成字符串Hello!a
,接着进行“"Hello!"+7
”运算,这也是一个字符串连接运算,得到结果是Hello!a7
对于第二个表达式,先进行“’a’+7”加法运算,其中’a’自动提升到int
类型,变成a对应的ASCII
值97,“97+7”将得到104,然后进行“104+”Hello!
“”运算,104会自动转换成字符串,将变成两个字符串的连接运算,从而得到104Hello!
。