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 虚拟机》课程,通过课后反思以及借鉴各位学友的发言总结,现整理出自己的知识架构,以便日后温故知新,查漏补缺。

关注本人公众号,第一时间获取最新文章发布,每日更新一篇技术文章。

02 Java 的基本类型的更多相关文章

  1. 016 01 Android 零基础入门 01 Java基础语法 02 Java常量与变量 10 布尔类型和字符串的字面值

    016 01 Android 零基础入门 01 Java基础语法 02 Java常量与变量 10 布尔类型和字符串的字面值 本文知识点:字面值 关于字面值的概念,需要注意:很多地方,我们可能就把字面值 ...

  2. 010 01 Android 零基础入门 01 Java基础语法 02 Java常量与变量 04 变量的三个元素的详细介绍之二——变量类型——即Java中的数据类型

    010 01 Android 零基础入门 01 Java基础语法 02 Java常量与变量 04 变量的三个元素的详细介绍之二--变量类型--即Java中的数据类型 Java中变量的三要素 变量名 变 ...

  3. 02 java包装类型的缓存机制

    02 java包装类型的缓存机制 Java 基本数据类型的包装类型的大部分都用到了缓存机制来提升性能. Byte,Short,Integer,Long 这 4 种包装类默认创建了数值 [-128,12 ...

  4. 关于java中Double类型的运算精度问题

    标题     在Java中实现浮点数的精确计算    AYellow(原作) 修改    关键字     Java 浮点数 精确计算   问题的提出:如果我们编译运行下面这个程序会看到什么?publi ...

  5. 关于java中Double类型的运算精度问题(转)

    Java Java double:浮点数:精确计算  public class Test{    public static void main(String args[]){        Syst ...

  6. Java-Runoob-高级教程-实例-方法:02. Java 实例 – 输出数组元素

    ylbtech-Java-Runoob-高级教程-实例-方法:02. Java 实例 – 输出数组元素 1.返回顶部 1. Java 实例 - 输出数组元素  Java 实例 以下实例演示了如何通过重 ...

  7. 205K+程序员关注过的问题:为什么不应该使用Java的原始类型?

    在逛 Stack Overflow 的时候,发现了一些访问量像熊耳山一样高的问题,比如说这个:为什么不应该使用Java的原始类型?访问量足足有 205K+,这不得了啊!说明有很多很多的程序员被这个问题 ...

  8. 02 java语言基础

    常量:字面值常量(字符串,字符,整数,小数,布尔,null),自定义常量,''这个不是字符常量,""这个是字符串常量 进制: 02.01_Java语言基础(常量的概述和使用) A: ...

  9. [02]java数据类型和运算符等知识

    00 Java中的注释 为了方便程序的阅读,Java语言允许程序员在程序中写上一些说明性的文字,用来提高程序的可读性,这些文字性的说明就称为注释.注释不会出现在字节码文件中,即Java编译器编译时会跳 ...

随机推荐

  1. Python +selenium之集成测试报告与unittest单元测试

    随着软件不断迭代,对应的功能也会越来越多,从而对应的测试用例也会呈指数增长.如果将全部的测试用例集成在一个文件中就会显得特别的臃肿而且维护成本也会很高. 一个很好的放大就是将这些测试yo你给里按照功能 ...

  2. JavaSe-算数运算符

    算数运算符包括:+.-.*./.%.++.-- 代码: package com.java.chap02; public class Demo07 { public static void main(S ...

  3. LibreOJ #515. 「LibreOJ β Round #2」贪心只能过样例

    题目描述 一共有 nnn个数,第 iii 个数 xix_ix​i​​ 可以取 [ai,bi][a_i , b_i][a​i​​,b​i​​] 中任意值.设 S=∑xi2S = \sum{{x_i}^2 ...

  4. MovieReview—Kingsman THE SECRET SERVICE(王牌特工之特工学院)

    Brain Storming         Mr. Valentine's Day see excess human beings as the Earth's virus and try to e ...

  5. Array - Two Sum

    import java.util.HashMap; import java.util.Map; /** * 分析: * 普通实现-嵌套循环两次,时间O(n2),空间O(1) * 复杂实现-循环一次,时 ...

  6. 设置DataGridView单元格的文本对齐方式

    实现效果: 知识运用: DataGridViewCellStyle类的Alignment属性     //获取或设置DataGridView单元格内的单元格内容的位置 public DataGridV ...

  7. 动态代理--Cglib

    JDK 的Proxy 实现,需要代理对象实现接口: package com.utils; import java.lang.reflect.InvocationHandler; import java ...

  8. NOIP模拟赛 密室逃脱

    密室逃脱(maze.*) 即使czhou没有派出最强篮球阵容,机房篮球队还是暴虐了校篮球队.为了不打击校篮球队信心,czhou决定改变训练后的活动.近来,江大掌门的徒弟徒孙们纷纷事业有成,回到母校为机 ...

  9. k8s基于canel的网络策略

    Kubernetes能够把集群中不同Node节点上的Pod连接起来,并且默认情况下,每个Pod之间是可以相互访问的.但在某些场景中,不同的Pod不应该互通,这个时候就需要进行访问控制.亲测:在kube ...

  10. C# WPF 粘贴板记录器

    工作学习中需要搜索很多资料,有建立文档对遇到过的问题进行记录,但是一来麻烦,二来有些当时认为不重要的事情,也许一段时间后认为是重要的,需要记录的,却又一时找不到,浪费时间做重复的事情.正好借着这个机会 ...