Java常量池 关于int类型数值的一些疑问的探究

前言

这里是我在学习常量池相关知识时遇到的一些问题。


在Java编译器编译Java文件时,会把字面量符号引用加入到class文件的常量池中。

我们是针对int类型的值和long、double、float等类型的值进行比较。
上面我们可以看到基本数据类型的值会加入到常量池中,那我们就来看一下是否如此:

public class ConstPoolCase {
    int a = 1;
    float b = 1f;
    double c = 2d;
    long d = 3L;
    public static void main(String[] args) {
        //todo
    }
}

上面是一个很简单的例子,接下来我们使用javap -verbose来查看一下class文件。


我们可以清楚地看到long、double、float型的数值确实是加入到了常量池当中,可是int型呢,int型的数值怎么没有出现在常量池当中。
为了一探究竟,所以我决定通过相关的字节码指令,查看这些普通基本类型是如何被赋值的。如图:

我们可以看到int型使用的指令和其他三种类型不太相同,其他三种类型基本上是类似的指令操作。
我们来看一下这些指令的作用:

iconst_1作用是将int型(1)推送至栈顶,该指令属于const系列,该系列的命令主要是负责将简单的数值推送到栈顶,该系列的命令是不需要带参数的。

首先通过通过iconst_1指令将int型的1推送至栈顶,再通过putfiled指令,将1赋值给了字段a,由此可以知道,如果int类型的数值如果比较简单的话,是不会将该值放入常量池中的,可以直接通过JVM指令将值赋值给相应字段。

ldc: 将int, float或String型常量值从常量池中推送至栈顶。
ldc_w: 将int, float或String型常量值从常量池中推送至栈顶(宽索引)
ldc2_w: 将long或double型常量值从常量池中推送至栈顶(宽索引)
这三个指令是属于ldc系列的指令,该系列的指令负责将数值常量或String常量值从常量池中推送到栈顶。该命令后面需要给一个表示常量在常量池中位置(编号)的参数。

通过了解到ldc系列的指令,并且我们可以看到,ldc指令后面的参数#3,#5,#8是和第一幅图相对应的。
有没有注意到,ldc系列是可以将int型常量值从常量池中推送至栈顶的,那就是说,int型的数值其实是会加入到常量池中的。
带着这个疑问,我们继续来看一下push系列的指令。

bipush 将单字节的常量值(-128~127)推送至栈顶
sipush 将一个短整型常量值(-32768~32767)推送至栈顶
该系列命令负责把一个整形数字(长度比较小)送到到栈顶。该系列命令有一个参数,用于指定要送到栈顶的数字。
注意该系列命令只能操作一定范围内的整形数值,超出该范围的使用将使用ldc命令系列。

看到这里我们就恍然大悟了,原来JVM字节码的指令是可以存储一定范围的值的,不需要将该范围内的值放置到常量池当中,然后搞个索引指向常量池中。
我们来验证一下:

public class ConstPoolCase {

    int a = 32768;
    float b = 11f;
    double c = 12d;
    long d = 3L;

    public static void main(String[] args) {
        //todo
    }
}

我们将int的值设置为32768,大于short型的最大值,可以看到,int型的数值出现在了常量池当中。
在这里插入图片描述
相应的字节码指令也变成了ldc.
在这里插入图片描述

由此可以得出结论:

对于const系列命令和push系列命令操作范围之外的数值类型常量,都放在常量池中的。

  • 8
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值