[TOC]
3.3 类型转换
内容导视:
- 基本数据类型转换
- 基本数据类型与 String 类型的转换
3.3.1 基本数据类型转换
缘起
double d = 3; 唉呀,字面量 3 不是被当作 int 类型处理吗?怎么就可以赋给 double 类型的 d?别急,看完以下实验就明白规则了。
boolean 除外,不同类型容量(取值范围)按从小到大排列:
byte -> short -> int -> long -> float -> double
char -> int -> long -> float -> double
基本数据类型的转换规则
前提:基本数据类型
当所赋值的字面量类型与变量的数据类型不一致时,会发生数据类型转换,从一种数据类型转成另一种数据类型。分为自动类型转换、强制类型转换。除了 boolean 类型不能参与转换,其他基本数据类型可以互相转换。
小容量赋给大容量,会发生自动类型转型,如 int 类型自动转为 long 类型:
// int 类型自动转换为 long
long l = 3;
// long 类型自动转为 float
float d = 3L;
System.out.println(d);// 3.0
// char 自动转 int
int i = '中';
System.out.println(i);// 20013
'中'在 Unicode 字库的序号是 4E2D,使用 UTF-16 编码存储的二进制码为 0100111000101101,即 20013。
大容量赋给小容量,自动转换无法进行:
// 错误: 不兼容的类型: 从 double 转换到 int 可能会有损失
int i = 3.13;
// 错误: 不兼容的类型: 从 long 转换到 int 可能会有损失
i = 3L;
// 错误: 不兼容的类型: 从 int 转换到 byte 可能会有损失
byte b = 532;
这时就需要强制转换符(),但可能会有精度损失。
// 强制把 double 类型转成 int
int i = (int)3.13;
System.out.println(i);// i = 3
// 强制把 long 类型转成 int
i = (int)3L;
System.out.println(i);// i = 3
// 强制把 int 类型转成 byte
byte b = (byte)532;
System.out.println(b);// b = 20
补充细节
1)如果字面量的值没有超出 byte、short、char 的取值范围,可以直接赋值给它们。(除了被当作 long 类型处理的字面量)
byte b = 3;
char c = 33;
byte b1 = 'a';// 'a' 表示 97
// 超出 byte 的取值范围,从 char 转换到 byte 可能会有损失
byte b2 = '中';// '中' 表示 20013
需要注意,我指的是以字面量形式赋值,而不是值传递,自己试试报什么错?
int i1 = 3;
int i2 = 33;
char letter = 'a';
byte b = i1;
char c = i2;
byte b1 = letter;
之前有人问你怎么知道 'a' 代表的整数,我又不想了解 ASCII 码,有什么简单的方法吗?这就是第 2 点,请看:
2)byte、short、char 类型的变量混算时,会自动升级到 int 类型。
怎么得出的这个结论?
byte b1 = 2;
byte b2 = 5;
byte b3 = b1 + b2;
Hello.java:6: 错误: 不兼容的类型: 从 int 转换到 byte 可能会有损失
byte b3 = b1 + b2;
是吧,两个 byte 类型的变量相加,竟然升级了。那我可以利用这一点,让 char 类型的变量升级成 int 变量,自然就知道该字符对应的整数了。
char c = '中';
short s = 0;
System.out.println(c + s);// 20013
System.out.println('1' - 0);// 49
3)多种类型混算时,先把字面量转成容量大的那种数据类型,再进行计算。
如果你不知道这点,以后计算很容易吃亏。比如 10 / 4,你本来想得到 2.5,但是这参与运算的数,容量最大的也只是 int 类型,而 int 类型只能保存整数,所以 2.5 被削去了小数。
int i = 10 / 4;
System.out.println(i);// i = 2
这时就需要浮点类型的参与,改一下:
double i = 10.0 / 4;
System.out.println(i);// i = 2.5
思考如下语句可以通过编译吗?
byte b = 10;
b = b * 2;
b 保存的 10 对应 byte 类型,2 对应 int 类型,这就是混算;让 10 升级到 int 类型,与 2 相乘,结果还是 int 类型,再赋给 byte 类型的变量,报错:从 int 转换到 byte 可能会有损失
思考输出什么?
double d = 1 / 4 * 4.0;
System.out.println(d);
有人说这不就是 1 吗?有什么难的?当然也有其他人看出来了:1 / 4 是两个 int 类型的字面量参与运算,结果为 0;(你难道忘了 int 类型只能保存整数吗?)接着算,0 * 4.0 = 0.0;
所以结果为 0.0。(忘记带小数,哪怕只是 .0,结果就完全不同)
你的原意可能是这:double d = 1.0 / 4 * 4.0;
3.3.2 基本数据类型与 String 类型的转换
没想到吧,"+" 号除了能计算两数之和外,还能拼接字符串。哦,我好像之前已经用过了。
String str1 = "我";
String str2 = "和";
String str3 = "你";
String str4 = str1 + str2 + str3;
System.out.println(str4);// 我和你
思考输出什么?
System.out.println(4 + 3 * 2 + "2" + 5 * 5);
4 + 6 = 10;10 + "2" = "102";"102" + 25 = "10225";
没看晕吧?从左至右,乘号优先;字符串加谁,谁就被拼接在一起。那么就利用这个 "+",将基本数据类型转成字符串吧。
基本数据类型转成字符串
"" 代表空字符串。输出字符串时,是不会输出双引号的,这你应该早就知道了。
long l = 3L;
int i = 3;
char c = '中';
double d = 3.243;
String str1 = l + "";
String str2 = i + "";
String str3 = c + "";
String str4 = d + "";
System.out.println(str1);// 3
System.out.println(str2);// 3
System.out.println(str3);// 中
System.out.println(str4);// 3.243
字符串转成基本数据类型
别看,等到包装类时就懂了。(或者你会查 API 文档,它们在 java.lang 包下)
String str = "123";
byte num1 = Byte.parseByte(str);
short num2 = Short.parseShort(str);
int num3 = Integer.parseInt(str);
long num4 = Long.parseLong(str);
float num5 = Float.parseFloat(str);
double num6 = Double.parseDouble(str);
/*
取下标为 0 的字符(得到 str 的第一个字符)
下标是从 0 开始,以 1 递增,并不是从 1 开始哦
*/
char num7 = str.charAt(0);
// 如果解析不是"true"的字符串,那么返回结果是 false
boolean num8 = Boolean.parseBoolean("true");
System.out.println(num1);// 123
System.out.println(num2);// 123
System.out.println(num3);// 123
System.out.println(num4);// 123
System.out.println(num5);// 123.0
System.out.println(num6);// 123.0
System.out.println(num7);// 1
System.out.println(num8);// true
注意不要想着把字符串 "abc" 转成整数,编译虽然可以通过,但运行时会报 java.lang.NumberFormatException 异常(数字格式化异常),程序会在抛出异常的位置终止执行。(异常中有讲)
编译时只是检查语法,并不会解析 "abc" 是否能够转成整数。