基本类型的类型转换
1.引言
Java提供了8种基本数据类型,分别用于存储整型、浮点型和布尔型数据,如下图所示:
每种基本数据类型占用的内存空间不同,如下表所示:
基本数据类型 | 大小 |
---|---|
byte | 1字节 |
short | 2字节 |
char | 2字节 |
int | 4字节 |
long | 8字节 |
float | 4字节 |
double | 8字节 |
Java语言规范没有强制指定boolean类型变量占用的内存空间。
在使用变量时常常需要转换其类型,Java提供的7种数值型之间可以相互转换,转换分为 自动类型转换 和 强制类型转换 两种。
2.自动类型转换
基本介绍
如果Java支持将某种类型的数据直接赋给另一种数据类型的变量,这种方式的类型转换称为 自动类型转换(Automatic Conversion) 或者 隐式类型转换(Implicit Conversion) 或者 扩大转换(Widening Conversion) 。下图中,箭头左边的数据类型可以自动转换成箭头右边的数据类型。
大部分的自动类型转换不会丢失数据的信息(但在int -> float、long -> float或long -> double时可能会丢失部分精度;在不使用strictfp关键字修饰的float转换为double时,也可能丢失部分信息)。
下面代码展示了几种自动类型转换的情况:
public class Test {
public static void main(String[] args) {
int i = 10;
// int -> long
long l = i;
// int -> float
float f = i;
System.out.println("int value: " + i); // 输出:int value: 10
System.out.println("long value: " + l); // 输出:long value: 10
System.out.println("float value: " + f); // 输出:float value: 10.0
}
}
整型数据的转换原理
将一个 有符号整型 数据在 整型范围内 进行自动类型转换的原理就是根据其 补码(two’s complement) 的最高位补充指定长度的0或1,称为 符号扩展 。
将一个 char类型 数据在 整型范围内 进行自动类型转换的原理就是补充指定长度的0, 称为 零扩展 。(这是因为char是无符号整型)
例如将byte类型的数据a = -27转换为int类型的原理是:
- 将byte数据a表示为二进制补码的形式,即 11100101 (Java在保存负数时均保存其补码,运算也是基于其补码)
- 根据补码的最高位(符号位)补充0或1,即 11111111 11111111 11111111 11100101
- 将该转换为int后的补码换算成原码,再转换为十进制,仍为 -27
String Context
有一种比较特殊的情况,当用运算符‘+’将基本数据类型与字符串值相连时,基本数据类型自动转换成字符串类型。因此, 将基本数据类型转换成字符串类型的一种简单方法就是,使用‘+’将其与一个空字符串连接 。
基本用法如下面代码所示:
public class Test {
public static void main(String[] args) {
// 下面一行代码编译出错,整数10位int类型不能直接赋值给String
// String str1 = 10;
// 将整型10转化为字符串类型
String str2 = 10 + "";
System.out.println(str2); // 输出:10
// 拼接字符串
String str3 = "Te" + "st";
System.out.println(str3); // 输出:Test
// 先作加法运算,再转化为字符串
String str4 = 10 + 20 + "Test";
System.out.println(str4); // 输出:30Test
// 均转换为字符串
String str5 = "Test" + 10 + 20;
System.out.println(str5); // 输出:Test1020
}
}
3.强制类型转换
基本介绍
当将下图中箭头末端的数据类型转换为箭头指向的数据类型时,需要 强制类型转换,也称 显式类型转换(Explicit Conversion) 或 缩小转换(Narrowing Conversion) 。
需要注意的是强制类型转换可能会丢失信息或损失部分精度。
整型数据的转换原理
占内存空间大的整型数据强制转换为占内存空间小的整型数据会将多余位截断。
char转换为short时会将最高位解释为符号位,反之则解释为普通位。
例如将int类型的a = 233转换为byte类型,截断前24位,剩余的位的最高位为1,所以为负数的补码,转化为原码则为-23:
特殊情况
当将byte类型数据转换为char类型时,byte类型数据首先通过Widening Conversion转换为int类型,在通过Narrowing Conversion转换为char类型,这个特殊的过程称为Widening and Narrowing Primitive Conversion 。
浮点型数据的类型转换机制
浮点型数据转换成整型时将丢失小数部分,若浮点数整数部分超出该整数类型的范围,结果取 最接近的整数值
public class Test {
public static void main(String[] args) {
double x = 3.16;
double y = 1e18;
double z = -1e18;
// 浮点型转整型,丢失小数部分
int intX = (int) x;
System.out.println(intX); // 输出: 3
// 浮点型数值超出了int的范围,结果取最接近的整数值
int intY = (int) y;
System.out.println(intY); // 输出: 2147483647,即int的最大值
// 浮点型数值超出了int的范围,结果取最接近的整数值
int intZ = (int) z;
System.out.println(intZ); // 输出: -2147483648,即int的最小值
}
}
利用浮点数转整型数据的特性,可以巧妙地实现四舍五入的功能,如以下代码片段所示:
double x = 1.2;
System.out.println((int)(x + 0.5)); // 输出: 1
double y = 1.7;
System.out.println((int)(y + 0.5)); // 输出: 2
对于小数部分 < 0.5的浮点数,加上0.5后整数部分不会有变化,转换成整型数据后只保留没有变化的整数部分;而对于小数部分 ≥ 0.5的浮点数,加上0.5后产生进位,整数部分加1,转换成整型数据后保留了进位后的整数部分,由此实现了 四舍五入 的功能。
4.表达式类型的自动提升
Java类型的自动提升有如下规则:
表达式中的所有的byte类型、short类型和char类型都将被提升到int类型,如:表达式byte + short 的类型是int
整个算术表达式的数据类型自动提升到与表达式中最高等级操作数同样的类型,如表达式int + long + float + double 的类型是double
public class Test {
public static void main(String[] args) {
byte a1 = 1;
short a2 = 2;
// 下面这行代码出错,byte + short的类型是int
// short a3 = a1 + a2;
int a3 = a1 + a2;
System.out.println(a3); // 输出:3
int a4 = 1;
long a5 = 2L;
float a6 = 3.0F;
double a7 = 4.0;
// 该表达式类型为double
double a8 = a4 + a5 + a6 + a7;
System.out.println(a8); // 输出:10.0
}
}
注意: 表达式的类型将严格保持和表达式中最高等级操作数相同的类型,因此int / int的类型还是int。 如以下程序所示:
public class Test {
public static void main(String[] args) {
int a1 = 3;
int a2 = 2;
// 表达式仍为int类型,结果截去小数部分
System.out.println(a1 / a2); // 输出:1
}
}