大家好,我是七哥。

0x00 写在前面

常言道,byte 占 1 字节,short、char 两字节,在内存中真的是这样?

这个问题是我家小白提出来的 。之所以会提出这个问题是因为我们之前聊过在 Java 中两个 byte 类型的数字相加在 JVM 中会被自动的扩展成 int 类型,也算是深究了一次本源,查看了 Java 虚拟机的指令集,大家可以看下我们之前的这期视频:

【小白的困惑】 a=a+b 和 a+=b 有啥区别呢?这是个问题!

不得不夸赞下小白,这也太爱思考了吧 。 既然她爱学,咱就继续在搞一搞。 我先不告诉你答案,毕竟口说无凭,还是直接先看代码,看完你肯定就懂了。

0x01 反编译插件

这里我给出一个代码,不过需要反汇编,看下 JVM 指令集操作过程。

要查看字节码,一般需要先使用 javac 编译、在使用 javap 反汇编:

// 编译文件javac Test.java// 查看 Class 文件内容javap -verbose Test

这里我们可以使用这个 jclasslib 插件,这个插件简直是深入学习必备的神器,就不藏私了,分享给大家 。

比 JDK 自带的 javap 好用些的,直接在 IDEA 中搜索 jclasslib 即可,编译后点击 View - Show Bytecode With Jclasslib 即可:

温馨提示:在使用插件查看字节码前,一定要先在 IDEA 中 点击 build project。

插件反编译后的结果如下:

相信你也和我一样,对于 JVM 没有深入学习过,看这个指令集操作码很多头大:宝宝看不懂呀 !

你的头发我来守护,这个问题 jclasslib 插件都替你想到了,直接点击对应的指令集操作码,就会自动跳转到官方的虚拟机规范,而且还会匹配到对应的章节:

跳转之后的页面:

贴心吧,强烈推荐 !

0x02 指令集操作码

对照反汇编之后的字节码,可以看到第一行是将局部变量 byte 类型的 7 压入操作数栈,使用的是 bipush 指令,来咱们来看下 bipush 指令 jvms-6.5.bipush的描述:

描述的意思是:byte 类型直接被符号扩展为 int 类型值,该值被压入操作数堆栈。

这里为什么 short 类型的变量会用 bipush 这个指令呢?看描述它是用来操作 byte 类型的,你应该也想到了吧:由于属于 ~128-127,编译时就转为了 byte 类型,所以使用 bipush 将 7 压入操作数栈。

咱们继续看下 iload 指令:

它描述的意思是将一个 int 类型的局部变量值压入操作数栈中。

然后还用到了这个 i2s 的指令, jvms-6.5.i2s,它是这样描述的:

操作数堆栈顶部的值必须为 int 类型。它从操作数堆栈中弹出,被截断为一个 short 值,然后符号扩展为一个 int 结果,结果被压入操作数堆栈。

所以,你看 JVM 中指令集这些操作的都是 int 类型的数据,因此在编译运行时 short 类型乃至 byte、char、boolean 类型的数据都会被提升为 int ,所以它们都是占用 4 个字节的。

实际上虚拟机规范中也只有 4 字节和 8 字节,Java栈是 32 位插槽的后进先出堆栈,在Java 栈上分配内存的最小单位 slot 槽大小就是 4 字节。

我猜 JVM 虚拟机的槽设计为 4 字节很大原因是当时主流的是 32 位操作系统, CPU 只能 32 位 32 位的寻址。

0x03 何不都用 int 省事

这个时候你可能会问:那我们平时说的一个 byte 占用1字节岂不是错误,按照JVM 指令集说的,byte大部分都要转为int,要这个有啥意义呢?不如全部都用 int 省事。

这个问题问滴很到位呀!

虽然对于栈上局部变量 byte、short、char 这些类型在内存中都是占用 4 字节,但是呀,注意这个但是,你别忘了数组对象呀,人家是分配在堆上的, 如果byte数组中每个元素都占用 4 字节就过分了,太浪费存储,毕竟栈生命周期短,计算完栈帧就回收了,在堆中byte 就是 1 字节,short 就是 2 字节的。

0x04 总结

byte、short 这些类型当做局部变量使用时,就是在栈上分配占用一个槽的大小也就是 4 字节。但在数组中使用时,是存储在堆上,会被优化 byte 就是 1 字节 short 就是 2 字节,但是当从数组中取出元素放入栈帧中运算时又被转成 int 占用4 字节。

好了今天就分享到这里,你学废了么。 看到这里就给

点个赞吧,持续分享 Java 技术干货和编程经验。
分类: 游戏攻略 标签: 暂无标签

评论

暂无评论数据

暂无评论数据

目录