问题
下面程序会打印什么呢?
public class Multicast {
public static void main(String[] args) {
System.out.println((int)(char)(byte)-1);
}
}
解答
该程序打印的是 65535,为什么呢?
首先列几条基础知识:
- int 有符号,32位;char无符号,16位;byte有符号,8位。
- 整数的默认类型为int,即问题中的-1为int类型。
- 不同基本类型之间的强制转换时,我们这样称呼这种转换:
窄化 <————————————> 拓宽
byte,short,char—> int —> long—> float —> double
我们来逐步分析这个程序:
1. 从 -1
开始
-1
是一个 int
类型的字面量,在 Java 中占 4 个字节(32 位),二进制补码表示为:
2. 强制转换为 (byte)-1
byte
类型占 1 个字节(8 位),转换时截取低 8 位:
这仍然是 -1
(在 byte
类型中)。
3. 强制转换为 (char)(byte)-1
char
在 Java 中是 无符号 16 位 整数类型。
现在要把 byte
类型的 -1
(值为 11111111
)转换为 char
。
首先,byte
类型在转换为 char
(或 int
等)时会先进行 符号扩展 到 int
,然后再截取低 16 位赋给 char
。
byte
值 -1
(二进制 11111111
)符号扩展到 int
:
然后转换为 char
时取低 16 位:
对于 char
(无符号)来说,这个二进制值表示 65535(因为 0xFFFF
的无符号值是 65535)。
4. 强制转换为 (int)(char)...
char
值 65535
(\uFFFF
)转换为 int
时,因为 char
是无符号的,所以直接零扩展为 int
:
即 65535
。
5. 最终输出
Java 类型转换系统
1. 拓宽基本类型转换 (Widening Primitive Conversion)
定义
将小范围类型转换为大范围类型,不会丢失信息。
转换规则(按顺序)
特点
- 不会丢失数值信息
- 可能损失精度(long → float, int → float)
- 自动进行,不需要显式转换
示例
2. 窄化基本类型转换 (Narrowing Primitive Conversion)
定义
将大范围类型转换为小范围类型,可能丢失信息。
转换路径
double → float
float → long, int, short, char, byte
long → int, short, char, byte
int → short, char, byte
short → char, byte
char → byte, short
特点
- 可能丢失信息和精度
- 必须显式强制转换
- 使用截断规则
示例
double d = 123.456;
int i = (int)d; // 结果为 123(截断小数部分)
long l = 300;
byte b = (byte)l; // 结果为 44(300 % 256)
3. 符号扩展 vs 零扩展
符号扩展 (Sign Extension)
- 用于有符号类型的拓宽转换
- 用原数值的符号位填充高位
- 保持数值的符号和大小不变
byte b = -1; // 二进制: 11111111
short s = b; // 符号扩展: 11111111 11111111 (-1)
int i = b; // 符号扩展: 11111111 11111111 11111111 11111111 (-1)
零扩展 (Zero Extension)
- 用于无符号类型的拓宽转换
- 用0填充高位
- 对于正数,值与符号扩展相同;对于负数,结果不同
char c = '\uFFFF'; // 二进制: 11111111 11111111 (无符号 65535)
int i = c; // 零扩展: 00000000 00000000 11111111 11111111 (65535)
4. 特殊转换规则
byte → char 的特殊处理
byte b = -1; // 11111111
char c = (char)b; // 实际过程:
// 1. byte → int: 符号扩展 → 11111111...11111111
// 2. int → char: 截取低16位 → 11111111 11111111
// 结果: '\uFFFF' (65535)
char → 数值类型的转换
5. 实际应用示例
原问题的完整分析
System.out.println((int)(char)(byte)-1);
// 步骤分解:
// 1. -1 (int): 11111111 11111111 11111111 11111111
// 2. (byte)-1: 11111111 (截取低8位)
// 3. (char)(byte)-1:
// - byte → int: 11111111 11111111 11111111 11111111 (符号扩展)
// - int → char: 11111111 11111111 (截取低16位)
// 结果: '\uFFFF' (65535)
// 4. (int)(char): 00000000 00000000 11111111 11111111 (零扩展)
// 最终输出: 65535
常见陷阱
byte b = -1;
char c = (char)b; // 结果是 65535,不是 -1
int i = c; // 结果是 65535
int j = (short)b; // 结果是 -1 (符号扩展)
6. 总结表
转换类型 | 是否显式 | 信息丢失 | 扩展方式 |
---|---|---|---|
拓宽转换 | 自动 | 可能损失精度 | 符号/零扩展 |
窄化转换 | 必须显式 | 可能丢失信息 | 截断 |
理解这些规则对于处理二进制数据、网络编程和类型安全至关重要。
code
more code
~~~~