今天遇到一个很有意思的问题:
1 | Object i = 1 == 1 ? new Integer(3) : new Float(1); |
显然1==1
是成立的,所以应该执行new Integer(3)
,按我自己的想法,最后的结果应该是3,但是显然这个问题没有这么简单(我好菜啊,无能狂怒中……)。
我运行了这段代码,惊讶的发现结果既不是3,更不是1.0,而是3.0,显然是Integer类型向Float类型发生了转换。之后我又做了一个实验:
1 | Object i = 1 == 1 ? new Float(3) : new Double(1); |
最后输出的是一个Double
类型。
之后我上网查阅了一些资料,发现这是一个数值类型提升的机制,数值提升用于将算术运算中的操作数转换为一个相同的类型以便于运算。
自动类型转换的前提是两种类型是彼此兼容的,并且转换的目的类型占的空间范围一定要大于转化的原类型。
正向转换:由低字节向高字节自动转换
byte
→ short
→ int
→ long
→ float
→ double
逆向转换:使用强制转换,可能会失精。
int a = (int)1.5
一元数值提升
某些运算符将一元数值提升用在了单操作数运算中,其必定能得到一个数字类型的值,规则如下:
- 当操作数是编译类型
Byte
、Short
、Character
或Integer
,那么它会先拆箱为对应的原始类型,然后拓宽为int
类型。 - 当操作数为编译类型
Long
、Float
或Double
,那么就直接拆箱为对应的原始类型。 - 当操作数是编译类型
byte
、short
、char
或int
,则直接拓宽为int
类型
一元数值提升主要用在以下情境中(提升为int
)
- 数组创建表达式的维度
- 数组索引表达式的索引
- 正号运算符(+)的操作数
- 符号运算符(-)的操作数
- 按位补运算符(~)的操作数
- 移位运算符(>>, >>>, << )的每一个操作数。注意移位运算并不会使两边的操作数提升到相同类型,如 A << B 中若B为
long
类型,A并不会被提升到long
。
注意:自增和自减单目运算符同样也会进行类型提升,但运算后会自动进行强制类型转换,如
byte a = 127; a++; // a在运算后为int类型,转为byte截断后变成-128
等价于byte a = (byte)128;
二元数值提升
当二元运算符的操作数皆可转化为数字类型时,那么将采用如下二元数值提升规则:
- 如果任一操作数为引用类型,那么对其进行自动拆箱。
- 拓宽类型转换被应用于以下情况:
- if 某一操作数为
double
类型,那么另一个也转为double
- else if 某一操作数为
float
类型,那么另一个也转为float
- else if 某一操作数为
long
类型,那么另一个也转为long
- else 两个操作数都转为
int
- if 某一操作数为
二元数值提升应用于以下运算符上:
- 乘法运算符: * 、 / 、%
- 针对数字类型的加减运算符: + 、 -
- 数值比较运算符:< 、<= 、> 、>=
- 数值相等比较运算符: == 、 !=
- 整数按位运算符: & 、^ 、|
条件运算符(? :)中的类型提升
条件表达式最终产生的类型取决于下述情况:
if 第二个操作数和第三个操作数有相同的类型(可以都为null),那么它就是条件表达式的类型。
else if 两个操作数中有一个的类型为原始类型T,而另一个为T的装箱类型,那么条件表达式的类型就是T。
else if 其中一个操作数是编译时null类型,另一个为引用类型,那么条件表达式的类型就是该引用类型。
else if 两个操作数都可转化为数字类型,那么分为以下情况:
- if 其中一个类型为
byte
或Byte
,另一个类型为short
或Short
,那么条件表达式类型为short
。 - else if 其中一个类型为T,T为
byte
、short
或char
,另一个类型为int
类型的常量表达式,且可用T来表达(在T可表示的范围内),那么条件表达式类型为T。 - else if 其中一个类型为T,T为
Byte
、Short
或Character
,另一个类型为int
类型的常量表达式,且可用U来表达(U为T的拆箱类型),那么条件表达式类型为U。 - else 对两个操作数使用二元数值提升机制(并没有真的去转换类型),得到的相同数值类型就是条件表达式的类型。
- if 其中一个类型为
以上操作仅用于编译器判断条件表达式的最终类型T,只有在最终选择的操作数(第二个表达式的或第三个表达式的)与T不符时才会进行自动拆箱/类型提升操作。
运算中的类型提升通常都是将低于int
位数的类型提升为int
,高于int
的拆箱后保持不变,两边操作数位数不同则升为高精度的那一个类型。
参考链接:https://blog.csdn.net/yangcheng33/article/details/76408580