前言
本篇文章持续学习字节码指令集中的类型转换指令,看看具体指令是怎么操作数据类型转换?
一、类型转换指令的概述
类型转换指令能够将 两种不同的数值类型进行互相转换
这些转换操作个别用于实现 用户代码中的显式类型转换操作
,或者用来解决 字节码指令集中数据类型相干指令无奈与数据类型
一一对应的问题。
次要有以下两种类型转换:宽化类型转换与窄化类型转换
二、类型转换指令的宽化类型转换
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 值。