JVM-Java 的基本类型
Posted java程序员笔记
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JVM-Java 的基本类型相关的知识,希望对你有一定的参考价值。
Java 的基本类型
Java 包括了八种基本类型,明细如下:
Java 的基本类型都有对应的值域和默认值。byte,short,int,long,float以及double的值域依次扩大,前面的值域都被后面的值域包括在内。所以,从前面的基本类型转换成后面的基本类型,无需强制转换。补充:尽管它们的默认值表示不一样,但是在内存中都是 0.
boolean 和 char 是唯二的无符号类型。boolean 的取值范围是 0 或者 1,char 类型的取值范围是 [0,65535]。通常可以认定 char 类型的值为非负数,这种特性十分有用,比如说作为数组的索引等。
局部变量也可以存储超出它们取值范围的数值,但是这些超出取值范围的数字会带来一些麻烦。例如: char 类型的局部变量实际上有可能是负数。但是在正常使用 Java 编译器的情况下,生成的字节码会遵守 Java 虚拟机规范对编译器的约束,因此无需过分短信局部变量会超出他们的取值范围。
浮点类型中的 float,通常有两个 0,+0.0F 和 -0.0F。这两个 0 的表示,在内存中的数值是不同的,但是在 Java 中 +0.0F == -0.0F 会返回真。有了这两者,我们就可以定义浮点数中的正无穷和负无穷。
任意正浮点数 (不包括 +0.0F) 除以 +0.0F 得到的值就是正无穷,内存中的值为 0x7F800000 任意负浮点数 (不包括 -0.0F) 除以 -0.0F 得到的值就是负无穷,内存中的值为 0xFF800000
[0x7F800001,0x7FFFFFFF] 和 [0xFF800001,0xFFFFFFFF] 对应的数值都是 NaN。一般我们计算得出的 NaN,比如说通过 +0.0F/-0.0F 得出的内存值为 0x7FC00000,这个数值我们称之为标准的 NaN,其他的统称为不标准的 NaN。
NaN 有一个特性:除了 "!=" 始终返回 true 以为,所有其他的比较结果都会返回 false。例如: "NaN < 1.0F" ,"NaN > 1.0F" 返回 false。对于任意浮点数 f ,无论它是 0 还是 NaN,"f != NaN" 始终返回 true。
Java 基本类型的大小
Java 虚拟机每调用一个 Java 方法的时候,都会创建一个栈帧。为了方便理解,只讨论供解释器使用的解释栈帧。
这种栈帧包含两个部分:局部变量区和字节码的操作数栈。这里的局部变量指的是广义的,包含普通意义下的局部变量,还包含实例方法中的 "this指针" 以及方法接受到的参数。
下面总结基本类型的存储。
在 Java 虚拟机规范中,局部变量区等价于一个数组,并且可以用正整数来索引。除了 long 和 double 的值需要两个数组单元来存储之外,其他的基本类型以及引用类型的值均占用一个数组单元。也就是说,boolean,byte,chart,short 这四种类型在栈上占用的空间和 int 是一样的,和引用类型也是一样的。因此,在 32 位的 HotSpot 中,这些类型在栈上将占用 4 个字节,而在 64 位的 HotSpot 中,他们将占 8 个字节。
上述情况进存在于局部变量,并不会出现在存储于堆中的字段或者数组元素上。对于 byte,chart,short 这三种类型的字段或者数组单元,它们在堆上占用的空间分别是 1 字节,2 字节,2 字节,跟它们的值域是相吻合的。
将一个 int 类型的值存储到这些类型的字段或者数组时,相当于做了一次隐式的掩码操作。举例: int 类型的值存入声明为 char 类型的字段里时,由于该字段仅占两字节,所以高位字节便会被截取。
boolean 字段和 boolean 数组比较特殊。在 HotSpot 中,boolean 字段占用一字节,而 boolean 数组则直接用 byte 数组来实现。为了保证堆中 boolean 值的合法性, HotSpot 在存储时显示地进行掩码操作,也就说说只取低位 (最后一位) 的值存入 boolean 字段或数组中。
下面总结基本类型的加载。
Java 虚拟机的算数运算几乎全部依赖于操作数栈。也就是说需要将堆中的 boolean,byte,char 以及 short 加载到操作数栈上,而后将栈上的值当做 int 类型来运算。
对于 boolean 和 char 这两个无符号类型,加载伴随着零扩展。举例:char 大小为两个字节,加载时 char 的值会复制到 int 类型的低二字节,而高二字节则会用 0 来填充。
对于 byte 和 short 这两个类型来说,加载伴随着符号的扩展。举例:short 的大小为两个字节,加载时同样会将值复制到 int 类型的低二字节。如果 short 的值为非负数,即最高位为 0,那么 int 类型的值的高二字节会用 0 来填充,否则用 1 来填充。
扩展思考
public class Foo {
static boolean boolValue;
public static void main(String[] args) {
boolValue = true; // 将这个 true 替换为 2 或者 3,再看看打印结果
if (boolValue)
System.out.println("Hello, Java!");
if (boolValue == true)
System.out.println("Hello, JVM!");
}
}
分析上述代码第一打印结果,以及将 true 替换成 2 或者 3 的时候,打印结果又是什么。
第一次打印:(条件:boolValue = true)
Hello, Java!
Hello, JVM!
第二次打印:(条件:boolValue = 2)
第三次打印:(条件:boolValue = 3)
Hello, Java!
Hello, JVM!
原因是:boolean 保存在静态域中,制定了它的类型。为了保证堆中 boolean 值的合法性, HotSpot 在存储时显示地进行掩码操作,也就说说只取低位 (最后一位) 的值存入 boolean 字段或数组中。即:当 boolValue = 2 的时候,取最后一位值为 0 代表 false,当 boolValue = 3 的时候,取最后一位值为 1 代表 true。
问答
Q:为什么 boolean,byte,char 以及 short 在栈中存储的时候占用四个字节
变长数组不好控制,所以牺牲空间换取效率。
Q:基本类型在内存中默认值都是0,那么是如何区别是哪种类型数据的呢?
内存中不做区分,Java 程序想把它解读成什么类型,它就是什么类型。
Q:double 和 long 占用两个数组单位,64位的机器上,数组单位是8个字节,也就是说在解释栈上面它们占用了16个字节?
是的。占用但并没有用高八字节的空间。这个属于HotSpot的实现细节,偏向了快速访问而牺牲了耗费空间。
Q:使用基本类型能够在执行效率以及内存使用两方面提升软件性能?具体是什么原理呢?
占的空间更小,不需要类型转换。
总结
本文创作灵感来源于 极客时间 郑雨迪老师的《深入拆解 Java 虚拟机》课程,通过课后反思以及借鉴各位学友的发言总结,现整理出自己的知识架构,以便日后温故知新,查漏补缺。
以上是关于JVM-Java 的基本类型的主要内容,如果未能解决你的问题,请参考以下文章