深入拆解java虚拟机(三):java的基本类型

  本章谈谈java的基本类型,在此之前插个额外话题,关于java代码的跨平台,大多数人都知道跨平台是基于字节码文件和JVM而完成的功能,其实java语言规范也做了些贡献,比如本章要涉及的java基本类型,在java语言规范里规定了基本类型的值域大小,在任意平台下都是固定的,这是其他高级语言没有实现的,比如整型int,c++在32位与64位系统下可能值域大小就不一致,导致无法跨平台。

  回归正题,本章内容主要参考极客时间《深入拆解java虚拟机》。

  java语言是面向对象开发语言,万物皆对象,实际上还是引进了八大基本类型,用来支持数值计算。java这么做的原因主要是工程上的考虑,因为使用基本类型能够在执行效率以及内存使用两方面提升软件能力(如何提升,还待日后调研)。

  java虚拟机的Boolean类型

  首先,看看java语言规范以及java虚拟机规范是怎么定义Boolean类型的。

  在java语言规范中,Boolean类型的值只有两种可能,它们分别用符号“true”和“false”来表示。显然,这两个符号是不能被虚拟机直接使用的。

  在java虚拟机规范中,Boolean类型则被映射成int类型。具体来说,“true”被映射成为正数1,而“false”被映射成为整数0.这个编码规则约束了java字节码的具体实现。举个例子,对于存储Boolean数组的字节码,java虚拟机需保证实际存入的值是整数1或者0。

  java虚拟机规范同时也要求java编译器遵守这个编码规则,并且用整数相关的字节码来实现逻辑运算,以及基于Boolean类型的条件转换,这样一来,在编译成的class文件中,除了字段和传入参数外,基本上看不出Boolean类型的痕迹。

  java的基本类型

  除了上面提到的Boolean类型外,java的基本类型还包括byte short int long char float double。

  java的基本类型都有对应的值域和默认值,尽管他们的默认值看起来不一样,但在内存中都是0。

  这些基本类型中,Boolean和char是唯二的无符号类型。在不考虑违反规范的情况下,Boolean类型的取值范围是0或者1,char类型的取值范围则是【0,65535】。通常我们可以认定char类型的值为非负数,这一特性十分有用,比如说作为数组索引。

Java 基本类型的大小

  Java 虚拟机每调用一个 Java 方法,便会创建一个栈帧。为了方便理解,这里只讨论供解释器使用的解释栈帧(interpreted frame)。

  这种栈帧有两个主要的组成部分,分别是局部变量区,以及字节码的操作数栈。这里的局部变量是广义的,除了普遍意义下的局部变量之外,它还包含实例方法的“this 指针”以及方法所接收的参数。

  在 Java 虚拟机规范中,局部变量区等价于一个数组,并且可以用正整数来索引。除了 long、double 值需要用两个数组单元来存储之外,其他基本类型以及引用类型的值均占用一个数组单元。

  也就是说,boolean、byte、char、short 这四种类型,在栈上占用的空间和 int 是一样的,和引用类型也是一样的。因此,在 32 位的 HotSpot 中,这些类型在栈上将占用 4 个字节;而在 64 位的 HotSpot 中,他们将占 8 个字节。

  当然,这种情况仅存在于局部变量,而并不会出现在存储于堆中的字段或者数组元素上。对于 byte、char 以及 short 这三种类型的字段或者数组单元,它们在堆上占用的空间分别为一字节、两字节,以及两字节,也就是说,跟这些类型的值域相吻合。

  因此,当我们将一个 int 类型的值,存储到这些类型的字段或数组时,相当于做了一次隐式的掩码操作。举例来说,当我们把 0xFFFFFFFF(-1)存储到一个声明为 char 类型的字段里时,由于该字段仅占两字节,所以高两位的字节便会被截取掉,最终存入“\uFFFF”。

  boolean 字段和 boolean 数组则比较特殊。在 HotSpot 中,boolean 字段占用一字节,而 boolean 数组则直接用 byte 数组来实现。为了保证堆中的 boolean 值是合法的,HotSpot 在存储时显式地进行掩码操作,也就是说,只取最后一位的值存入 boolean 字段或数组中。

  讲完了存储,现在我来讲讲加载。Java 虚拟机的算数运算几乎全部依赖于操作数栈。也就是说,我们需要将堆中的 boolean、byte、char 以及 short 加载到操作数栈上,而后将栈上的值当成 int 类型来运算。

  对于 boolean、char 这两个无符号类型来说,加载伴随着零扩展。举个例子,char 的大小为两个字节。在加载时 char 的值会被复制到 int 类型的低二字节,而高二字节则会用 0 来填充。

  对于 byte、short 这两个类型来说,加载伴随着符号扩展。举个例子,short 的大小为两个字节。在加载时 short 的值同样会被复制到 int 类型的低二字节。如果该 short 值为非负数,即最高位为 0,那么该 int 类型的值的高二字节会用 0 来填充,否则用 1 来填充。

总结与实践

  今天介绍了 Java 里的基本类型。

  其中,boolean 类型在 Java 虚拟机中被映射为整数类型:“true”被映射为 1,而“false”被映射为 0。Java 代码中的逻辑运算以及条件跳转,都是用整数相关的字节码来实现的。

  除 boolean 类型之外,Java 还有另外 7 个基本类型。它们拥有不同的值域,但默认值在内存中均为 0。这些基本类型之中,浮点类型比较特殊。基于它的运算或比较,需要考虑 +0.0F、-0.0F 以及 NaN 的情况。

  除 long 和 double 外,其他基本类型与引用类型在解释执行的方法栈帧中占用的大小是一致的,但它们在堆中占用的大小确不同。在将 boolean、byte、char 以及 short 的值存入字段或者数组单元时,Java 虚拟机会进行掩码操作。在读取时,Java 虚拟机则会将其扩展为 int 类型。

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值