第12章 整数运算

12.1 二进制补码运算
Java虚拟机所支持的所有的整数类型-byte, short、int和long,它们都是带符号的二进制补码数。二进制补码方案既能够描述正整数,也能够描述负整数。在一个二进制补码数中,最重要的位就是它的符号位。符号位为1,表示负整数;符号位为0,表示正整数和数字0。

能够被二进制补码方案表示的数的范围为:2的总位数次幂。例如,在Java中,short类型是16位带符号的二进制补码整数。能够惟一表示的整数数为:216或者65536。short类型值范围的一半被用来表示0和正整数,另一半被用来表示负数。16位二进制补码负数的范围是-32768 (0x8000)~-1(Oxffff),零用0x0000来表示,整数的范围是 1 (0x0001)-32 767 (0x7fff)。
正整数直觉上只不过是数的两种表示法之一。负数可以通过负数和2的某次方幂相加而得出。 例如,short类型的长度为16位,因此二进制补码表示法可以通过一个负数和2的16次幂(或者 65 536)的相加来得到一个有效范围内(-32 768 — 1 )的负数。-1的二进制补码表示为65 536 + (-1 )或者65 535 (Oxffff)。-2 的二进制补码表示为 65 536 + (-2 )或者65 534 ( Oxfffe )。

在带符号二进制补码数上进行的加法运算与在无符号二进制数上进行的加法运算一样。两个数相加(忽略溢出),结果被解释为一个带符号二进制补码数。这个过程将在运算结果是在该类型的有效范围内的情况下进行。例如,要获得4+ (-2 )的结果,只要把0x00000004和 Oxfffffffe相加即可。结果是Ox100000002,但是因为int类型只有32位,于是溢出部分被忽略,结果为0x00000002。

Java虚拟机中出现的整数运算的溢出并不会导致抛出异常,其结果只被简单地截短以符合数据类型(或者为int类型,或者为long类型)。例如,把int类型值0x7fffffff和1相加,将会得到 0x80000000。因此,如果相加值的类型为int而非long, Java虚拟机中2 147 483 647加上1的结果将会是-2 147 483 648。在Java中编程时,必须随时注意可能发生的溢出。必须在每一种情况下 确认所选择的数据类型(int或者long)是否正确。整数被0除时会抛出一个ArithmeticException 异常,所以应该时刻牢记此类异常将会被抛出,必须在必要的时候捕获异常。

如果long类型的长度仍然不能满足需要,可以使用java.math包中的Biglnteger类,这个类的实例可以描述任意长度的整数。Biglnteger类支持在任意长度整数上进行的所有数学运算,前提是这些运算是基于java虚拟机和java.lang.Math包所支持的基本类型的

12.3运算操作码
Java虚拟机提供几种进行整数算术运算的操作码,它们执行基于int和long类型的运算。如前所述,当byte、short和char类型值参与算术运算时,首先会将它们转换为int类型。对于每一个执行int类型算术运算的操作码,在long类型的相同运算中有对应的操作码。

整数加法可以在int和long类型上进行。表12-1描述了完成下列任务的操作码:弹出栈顶部的两个值,相加,把结果压入找。必须有指令先把两个相加的值压人栈。值的类型由操作码自己指定,最后得到的结果总是与相加的成员具有同样的类型。这些操作码都不会导致任何异常抛 出,溢出在这里通常被忽略。

前面我们得到了这样一条规则:运算操作码从栈中取出它们的操作数,但在表12-2中显示了 —个例外情况,即iinc操作码对int类型局部变量的加法操作。用于加法运算的局部变量位于字节码流中紧接于iinc指令之后的第一个字节,将要加到局部变量上的值从iinc指令之后的第二个字节取出。第二个字节被解释为一个8位的带符号二进制补码数。局部变量和8位带符号值相加, 相加的结果被写回局部变量。这条操作码可以用来给局部变量赋-128 ~ 127之间的值。这条操作码与用于控制循环(for或者while)执行的变量的加减相比,效率更高。与加法指令一样,这里没有任何异常抛出,溢出通常被忽咯。

表12-2的第二行说明了iinc指令的wide变量。如第10章中所述,通过使用wide指令,可以把无符号局部变量索引从8位扩展到16位。使用16位索引的指令可以对多达65536个位置的变量寻址。在iinc指令的处理过程中,wide指令也是用来把带符号的增量值从8位扩展到16位。因此, iinc操作码的wide变量可以在-32768 - 32767范围内改变一个局部变量的值。

值得注意的是,该字节码序列描述了在Java字节码的桟结构内处理java源代码中boolean类型 的方式。存储在位置2的局部变量中的值表示源代码中的boolean foundPrime变量,它是—个int 类型。它通过压人一个int常量为1或者0的指令设置为true或者false;通过执行int类型值与0进行 比较的指令来检查boolean类型的值。

原文地址:https://www.cnblogs.com/mongotea/p/11980070.html

时间: 2024-11-04 19:28:59

第12章 整数运算的相关文章

《深入Java虚拟机学习笔记》- 第12章 整数运算

Java虚拟机提供几种进行整数算术运算的操作码,他们执行基于int和long类型的运算.当byte.short和char类型值参与算术运算时,首先会将它们转换为int类型.这些操作码都不会抛出异常,溢出在这里通常可以被忽略. 整数加法 操作码 操作数 说明 iadd (无) 从栈中弹出两个int类型数,相加,然后将所得int类型结果压回栈 ladd (无) 从栈中弹出两个long类型数,相加,然后将所得long类型结果压回栈 将一个常量与局部变量相加 操作码 操作数 说明 iinc vindex

《深入Java虚拟机学习笔记》- 第18章 finally子句

本章主要介绍字节码实现的finally子句.包括相关指令以及这些指令的使用方式.此外,本章还介绍了Java源代码中finally子句所展示的一些令人惊讶的特性,并从字节码角度对这些特征进行了解释. 1.微型子例程 字节码中的finally子句表现的很像"微型子例程".Java虚拟机在每个try语句块和与其相关的catch子句的结尾处都会"调用"finally子句的子例程.finally子句结束后(这里的结束指的是finally子句中最后一条语句正常执行完毕,不包括抛

《深入Java虚拟机学习笔记》- 第4章 网络移动性

Java虚拟机学习笔记(四)网络移动性 <深入Java虚拟机学习笔记>- 第4章 网络移动性,布布扣,bubuko.com

《深入Java虚拟机学习笔记》- 第7章 类型的生命周期

一.类型生命周期的开始 如图所示 初始化时机 所有Java虚拟机实现必须在每个类或接口首次主动使用时初始化: 以下几种情形符合主动使用的要求: 当创建某个类的新实例时(或者通过在字节码中执行new指令,或者通过不明确的创建.反射.克隆和反序列化): 当调用某个类的静态方法时(即在字节码中执行invokestatic指令): 当使用某个类或接口的静态字段,或者对该字段赋值时(用final修饰的静态字段除外,它被初始化为一个编译时常量表达式): 当调用Java API中的某些反射方法: 当初始化某个

《深入Java虚拟机学习笔记》- 第13章 逻辑运算

<深入Java虚拟机学习笔记>- 第13章 浮点运算 <深入Java虚拟机学习笔记>- 第13章 逻辑运算,布布扣,bubuko.com

《深入Java虚拟机学习笔记》- 第2章 平台无关

Java虚拟机学习笔记(二)平台无关 <深入Java虚拟机学习笔记>- 第2章 平台无关,布布扣,bubuko.com

《深入Java虚拟机学习笔记》- 第14章 浮点运算

<深入Java虚拟机学习笔记>- 第13章 浮点运算

《深入Java虚拟机学习笔记》- 第19章 方法的调用与返回

<深入Java虚拟机学习笔记>- 第19章 方法的调用与返回

《深入Java虚拟机学习笔记》- 第5章 Java虚拟机

一.JVM的生命周期 当启动一个Java程序时,一个Java虚拟机实例就诞生了:当该程序关闭退出时,这个Java虚拟机也就随之消亡: JVM实例通过调用某个初始类的main方法来运行一个Java程序:这个main方法必须是public.static的,而且返回值必须是void:任何一个拥有这样的main方法的类都可以作为Java程序运行的起点: Java程序初始类中的main方法,将作为该程序初始线程的起点,其它任何线程都是由这个初始线程启动的: 守护线程和非守护线程 守护线程通常是由虚拟机自己

《深入Java虚拟机学习笔记》- 第17章 异常

<深入Java虚拟机学习笔记>- 第17章 异常