Java语法特性隐藏在了代码中的每个角落,最常见的就是自动拆装箱和类型提升了。这些特性在带来编码便利性的同时也在代码中藏下了些不易察觉定时炸弹,比如对
null
拆箱时引发的空指针异常NPE。本文就将JLS中关于数值提升的机制译述出来,便于更深刻地理解代码后面的东西。
问题
以下几段代码为什么是这样的运行结果:
Object k = true ? null : 1;
System.out.println(k);
// 输出:
null
Integer a = null;
Object k = true ? a : 1;
System.out.println(k);
// 运行时报NPE错误
byte a = 2;
byte k = true ? a : 128;
System.out.println(k);
// 编译时报错。 不兼容的类型: 从int转换到byte可能会有损失
数值提升
数字类型提升机制被用于算术运算符上,通常使用场景为:
- 同一类型转换
虽然并无什么作用,但有时可以使代码更清晰。 - 拓宽原始类型转换
指byte、short、int、long、float、double由低向高转换。 - 自动拆箱转换
基础类型引用类的拆箱方法,如r.intValue()
。
数值提升用于将算术运算中的操作数转化为一个相同的类型以便于运算,具体分为两种情况:一元数值提升和二元数值提升。
一元数值提升
某些运算符将一元数值提升用在了单操作数运算中,其必定能得到一个数字类型的值,规则如下:
- if 操作数是
Byte
、Short
、Character
或Integer
,那么它会先自动拆箱为对应的原始类型,然后拓宽为int
类型。 - else if 操作数为
Long
、Float
或Double
,那么就直接自动拆箱为对应的原始类型。 - else if 操作数是
byte
、short
、char
或int
,那么就拓宽为int
类型。 - else 保持原样。
以上自动拆箱均可能出现NPE情况。