前言
本篇文章持续学习字节码指令集中的类型转换指令,看看具体指令是怎么操作数据类型转换?
一、类型转换指令的概述
类型转换指令能够将两种不同的数值类型进行互相转换
这些转换操作个别用于实现用户代码中的显式类型转换操作
,或者用来解决字节码指令集中数据类型相干指令无奈与数据类型
一一对应的问题。
次要有以下两种类型转换:宽化类型转换与窄化类型转换
二、类型转换指令的宽化类型转换
Java虚拟机间接反对以下数值的宽化类型转换(widening numeric conversion,小范畴类型向大范畴类型的平安转换)。也就是说并不需要指令执行,包含:
- 从int类型到long、float或者double类型。对应的指令为: i2l、i2f、 i2d。
- 从long类型到float、double类型。对应的指令为:l2f、l2d
- 从float类型到double类型。对应的指令为:f2d
简化为: int --> long --> float --> double
接下来咱们针对于宽化类型转换的根本测试,请看以下示例代码
public class classcastTest{ //宽化类型转换 //针对于宽化类型转换的根本测试 public void upcast1(){ int i = 10; long l = i; float f = i; double d = i; float fl = l; double d1 = l; double d2 - fl; }}
接下来咱们编译该代码,看看办法的字节码是用什么指令进行类型转换的?
精度损失问题
================================
宽化类型转换是不会因为超过指标类型最大值而失落信息的,例如从int转换到 long,或者从int转换到double,都不会失落任何信息,转换前后的值是准确相等的。
从int、long类型数值转换到float,或者long类型数值转换到double时,将可能产生精度失落:可能失落掉几个最低无效位上的值
,转换后的浮点数值是依据IEEE754最靠近舍入模式所失去的正确整数值。
接下来咱们针对于精度损失问题的根本测试,请看以下示例代码
public class classcastTest{ //举例;精度损失的问题@Test public void upcast2(){ int i = 123123123; float f = i; system.out.print1n(f); }}//运行后果如下:1.2312312E8
此时咱们再看看long类型转换为double类型,是否也会有如此的问题?
public class classcastTest{ //举例;精度损失的问题@Test public void upcast2(){ long l = 123123123123L; double d = l; ystem.out.print1n(d); }}//运行后果如下:1.2312312312312312E17
宽化类型转换实际上是可能产生精度失落的,然而这种状况不会导致Java虚拟机抛出运行时异样
补充阐明
================================
针对于从byte、char和short类型到int类型的宽化类型转换实际上是不存在的。
对于byte类型转为int 虚拟机没有做实质性的转化解决,只是简略地通过操作数栈替换了两个数据
而将byte转为long时,应用的是i21,能够看到在外部byte在这里曾经等同于int类型解决,相似的还有short类型,这种解决形式有两个特点:
一方面能够缩小理论的数据类型,如果为short和byte都筹备一套指令,那么指令的数量就会大增,而虚拟机目前的设计上,只违心应用一个字节示意指令,因而指令总数不能超过256个
,为了节俭指令资源,将short和byte当做int解决也在情理之中
另一方面因为局部变量表中的槽位固定为32位,无论是byte或者short存入局部变量表,都会占用32位空间。从这个角度说,也没有必要特意辨别这几种数据类型。
三、类型转换指令的窄型转换
转换规则
================================
Java虚拟机也间接反对以下窄化类型转换:
- 从int类型至byte、short或者char类型。对应的指令有: i2b、i2c、i2s
- 从long类型到int类型。对应的指令有:l2i
- 从float类型到int或者long类型。对应的指令有:f2i、f21
- 从double类型到int、long或者float类型。对应的指令有: d2i、d2l、d2f
接下来咱们针对于窄化类型转换的根本测试,请看以下示例代码
public class classcastTest{ ///窄化类型转换根本的应用 public void downcast1(){ int i = 10; byte b = (byte)i; short s = (short)i; char c = (char)i; long 1 = 10L; int i1 = (int)l; byte b1 = (byte)l; }}
接下来咱们编译该代码,看看办法的字节码是用什么指令进行类型转换的?
精度损失问题
================================
窄化类型转换可能会导致转换后果具备木同的正负号、不同的数量级,因而转换过程很可能会导致数值去失精度。
只管数据类型窄化转换可能会产生下限溢出、上限溢出和精度失落等状况,然而Java虚拟机标准中明确规雉数值类型的窄化转换指令永远不可能导致虚拟机抛出运行时异样
接下来咱们针对于精度损失问题的根本测试,请看以下示例代码
public class classcastTest{ //窄化类型转换的精度损失@Test public void downCast4(){ int i = 128; byte b = (byte)i; system.out.printin(b); }}//运行后果如下:-128
起因在于32位时的数据,转换数据时将高位砍掉只剩下byte的范畴,就变成正数了
补充阐明
================================
当将一个浮点值窄化转换为整数类型T(T限于int或long类型之一)的时候,将遵循以下转换规则:
- 如果浮点值是NaN,那转换后果就是int或long类型的0
- 如果浮点值不是无穷大的话,浮点值应用IEEE 754的向零舍入模式取整,取得整数值v
如果v在指标类型T(int或long)的示意范畴之内那转换后果就是v。否则将依据v的符号转换为T所能示意的最大或者最小
当将一个double类型窄化转换为 float类型时,将遵循以下转换规则:
通过向最靠近数舍入模式舍入一个能够应用float类型示意的数字。最初后果依据上面的规定判断:
- 如果转换后果的绝对值太小而无奈应用float来示意,将返回float类型的正负零。
- 如果转换后果的绝对值太大而无奈应用float来示意,将返回float类型的正负无穷大。
- 对于double类型的NaN值将按规定转换为float类型的NaN值。