目录

一、概述

二、宽化类型转换

三、窄化类型转换


一、概述

类型转换指令可以将两种不同的数值类型进行相互转换。(主要指除了boolean之外的七种类型)这些转换操作一般用于实现用户代码中的显式类型转换操作,或者用来处理字节码指令集中数据类型相关指令无法与数据类型一一对应的问题。

二、宽化类型转换

(一)、转换规则

Java虚拟机直接支持以下数值的宽化类型转换(小范围类型向大范围类型的安全转换)。也就是说,并不需要指令执行,包括:

  • 从int类型到long、float或者double类型。对应的指令为:i2l、i2f、i2d
  • 从long类型到float、 double类型。对应的指令为:l2f、l2d
  • 从float类型到double类型。对应的指令为:f2d

简化为如下图:

public void cast01() {int i = 10;long l = i;float f = i;double d = i;float f1 = l;double d1 = l;double d2 = f1;
}

通过jclasslib查看其字节码即分析如下图:

(二)、精度损失问题

  • 宽化类型转换是不会因为超过目标类型最大值而丢失信息的,例如,从int转换到long,或者从int转换到 double,都不会丢失任何信息,转换前后的值是精确相等的。
  • 从int、long类型数值转换到 float时,或者long类型数值转换到 double时,将可能发生精度丢失——可能丢失掉几个最低有效位上的值,转换后的浮点数值是根据IEEE754最接近舍入模式所得到的正确整数值。
  • 尽管宽化类型转换实际上是可能发生精度丢失的,但是这种转换永远不会导致ava虚拟机抛出运行时异常。
//举例:精度损失的问题
public static void upCast2() {int i = 123123123;float f = i;System.out.println(f); //123123120  精度丢失(1.2312312E8)long l1 = 123123123123L;double d1 = l1;System.out.println(d1);//不会发生精度丢失(1.23123123123E11)long l2 = 123123123123123123L;double d2 = l2;System.out.println(d2);//123123123123123120 精度丢失(1.2312312312312312E17)
}

(三)、补充说明

从byte、char和short类型到int类型的宽化类型转换实际上是不存在的。对于byte类型转为int,虚拟机并没有做实质性的转化处理,只是简单地通过操作数栈交换了两个数据。而将byte转为long时,使用的是i2l,可以看到在内部byte在这里已经等同于int类型处理,类似的还有short类型,这种处理方式有两个特点:

  • 一方面可以减少实际的数据类型,如果为short和byte都准备一套指令,那么指令的数量就会大增,而虚拟机目前的设计上,只愿意使用一个字节表示指令,因此指令总数不能超过256个,为了节省指令资源,将short和byte当做int处理也在情理之中;
  • 另一方面,由于局部变量表中的槽位固定为32位,无论是byte或者short存入局部变量表,都会占用32位空间。从这个角度说,也没有必要特意区分这几种数据类型;
public void cast03(byte b) {int i = b;long l = b;double d = b;
}

通过jclasslib查看字节码分析如下:

三、窄化类型转换

(一)、转换规则

Java虚拟机也直接支持以下窄化类型转换:

  • 从int类型至byte、 short或者char类型。对应的指令有:i2b、i2c、i2s
  • 从 long类型到int类型。对应的指令有:l2i
  • 从 float类型到int或者long类型对应的指令有:f2i、f2l
  • 从 double类型到int、long或 float者类型。对应的指令有:d2i、d2l、d2f

总结如下图所示:

public void cast04() {int i = 10;byte b = (byte) i;short s = (short) i;char c = (char) i;long l = 10L;int i1 = (int) l;byte b1 = (byte) l;
}

观察其字节码信息:

注意:s2b不存在,实际的情况处理为i2b。

public void cast05() {short s = 10;byte b = (byte) s;
}

(二)、精度损失问题

窄化类型转换可能会导致转换结果具备不同的正负号、不同的数量级,因此,转换过程很可能会导致数值丢失精度。

尽管数据类型窄化转换可能会发生上限溢出、下限溢出和精度丢失等情况,但是Java虚拟机规范中明确规定数值类型的窄化转换指令永远不可能导致虚拟机抛出运行时异常。

public void cast06() {int i = 128;byte b = (byte) i;       //byte 最大到127  转换后精度丢失,结果为-128System.out.println(b);   //-128
}

(三)、补充说明

【a】当将一个浮点值窄化转换为整数类型T(T限于int或long类型之一)的时候,将遵循以下转换规则:

  • 如果浮点值是NaN,因为int或者long没有NaN,转换结果就是int或long类型的0;
  • 如果浮点值不是无穷大的话,浮点值使用IEEE 754的向零舍入模式取整,获得整数值v,如果v在目标类型T(int或long)的表示范围之内,那转换结果就是v。否则,将根据v的符号,转换为T所能表示的最大或者最小正数;

【b】当将一个double类型窄化转换为 float类型时,将遵循以下转换规则:通过向最接近数舍入模式舍入一个可以使用 float类型表示的数字。最后结果根据下面这3条规则判断:

  • 如果转换结果的绝对值太小而无法使用 float来表示,将返回 float类型的正负零。
  • 如果转换结果的绝对值太大而无法使用 float来表示,将返回 float类型的正负无穷大。
  • 对于double类型的NaN值将按规定转换为 float类型的 NaN值。
public static void cast07() {double d1 = Double.NaN; //0.0 / 0.0int i = (int) d1;System.out.println(d1);     //NaNSystem.out.println(i);      //0 整型不存在NaN,按0处理double d2 = Double.POSITIVE_INFINITY;   // Infinitylong l = (long) d2;int j = (int) d2;System.out.println(l);  //9223372036854775807  转换后指向了long型的最大值  Infinity -> 9223372036854775807System.out.println(Long.MAX_VALUE); //9223372036854775807System.out.println(j);      //2147483647 转换后指向了int型的最大值  Infinity -> 2147483647System.out.println(Integer.MAX_VALUE);  //2147483647float f = (float) d2;System.out.println(f);      //Infinity   float无穷大没有具体值float f1 = (float) d1;System.out.println(f1);     //NaN
}

字节码指令之类型转换指令相关推荐

  1. [三] java虚拟机 JVM字节码 指令集 bytecode 操作码 指令分类用法 助记符

    说明,本文的目的在于从宏观逻辑上介绍清楚绝大多数的字节码指令的含义以及分类 只要认真阅读本文必然能够对字节码指令集有所了解 如果需要了解清楚每一个指令的具体详尽用法,请参阅虚拟机规范 指令简介 计算机 ...

  2. Java虚拟机专题之字节码指令(读书笔记)

    一 字节码与数据类型 大部分的指令都包含了其操作所对应的数据类型信息. 比如iload指令用于从局部变量表中加载int类型的数据到操作栈中,而fload指令加载的则是float数据类型的数据. 二 加 ...

  3. Java指令全集_Java的JVM字节码指令集详解

    本文详细介绍了如何使用javap查看java方法中的字节码.以及各种字节码的含义,并且配以完善的案例,一步步,从头到尾带领大家翻译javap的输出.在文末还附有JVM字节码指令集表. 本文不适合没有J ...

  4. JVM笔记:Java虚拟机的字节码指令详解

    1.字节码 Java能发展到现在,其"一次编译,多处运行"的功能功不可没,这里最主要的功劳就是JVM和字节码了,在不同平台和操作系统上根据JVM规范的定制JVM可以运行相同字节码( ...

  5. Java虚拟机字节码指令

    Java字节码指令 Java 字节码指令及javap 使用说明 ### java字节码指令列表 字节码 助记符 指令含义 0x00 nop 什么都不做 0x01 aconst_null 将null推送 ...

  6. Java 指令与字节码

    Java 指令与字节码 查看class文件 编写简单java代码 编译代码 查看class文件 Java字节码总的结构表 常量池 常量池容量计数器 字面量和符号引用 全限定名 简单名称 描述符 常量类 ...

  7. 【深入理解java虚拟机】 - JVM字节码指令介绍

    文章目录 什么是字节码指令 javap的用法 字节码与数据类型 字节码指令集 加载和存储指令 运算指令 类型转换指令 对象创建与访问指令 操作数栈管理指令 控制转移指令 方法调用和返回指令 异常处理指 ...

  8. 有哪些常见的字节码指令?

    写在前面 本文隶属于专栏<100个问题搞定Java虚拟机>,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢! 本专栏目录结构和文献引用请见100个问题搞定Java ...

  9. Java字节码指令大全

    Java二进制指令代码解析 Java源码在运行之前都要编译成为字节码格式(如.class文件),然后由ClassLoader将字节码载入运行.在字节码文件中,指令代码只是其中的一部分,里面还记录了字节 ...

  10. java字节码运行原理_JVM 内部原理(六)— Java 字节码基础之一

    JVM 内部原理(六)- Java 字节码基础之一 介绍 版本:Java SE 7 为什么需要了解 Java 字节码? 无论你是一名 Java 开发者.架构师.CxO 还是智能手机的普通用户,Java ...

最新文章

  1. IOS 总结:NSArray,NSSet,NSDictionary
  2. mysql 生明变量_在 MySQL 的 SQL 文件中,定义变量与使用变量
  3. 开发composer包
  4. 仅凭借一本薄薄的时间简史,征服了全球读者...
  5. python字典求平均值_Python - 字典中各个键的每个值的均值
  6. 智能门禁(7)----调用face++api实现人脸对比
  7. sphinx配置文件全解析
  8. 蓝桥杯 ADV-187 算法提高 勾股数
  9. C# 之 Stream 和 byte[] 的相关转换
  10. 单引号、双引号和不加引号区别
  11. 将多个csv文件整合到一个csv文件中
  12. c语言程序设计自考真题,自学考试《C语言程序设计》随堂试题及答案
  13. 综合能源管理服务认证是什么 , 综合能源服务认证有什么要求?
  14. STM32实现水下四旋翼(三)通信任务——遥控器SBUS通信
  15. 以淘宝为例,解析大型电商服务端架构!
  16. 将Linux 标准输出,错误输出重定向到文件
  17. hdu2476 字符串A-字符串-B
  18. Audio Effect
  19. Vue之filters传参问题
  20. c语言俄罗斯方块程序设计论文,c语言俄罗斯方块游戏程序设计报告

热门文章

  1. video-react报错pause没有被定义_qt常见报错
  2. vue选中点击的元素_vue.js - Vue 点击当前元素触发当前事件怎么做??
  3. 636. 函数的独占时间
  4. 561. 数组拆分 I
  5. DataType error: cannot resolve DataType of [[[D
  6. 凸优化第六章逼近与拟合 6.2最小范数问题
  7. Spring Cloud学习笔记---一分钟知晓Zuul
  8. org.apache.hadoop.hbase.mapreduce.Driver 导入数据到HBASE table
  9. 数学分析 复合函数求导法则
  10. Hadamard 分数阶微分/积分定义