前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >jdk源码分析之Integer--缓存

jdk源码分析之Integer--缓存

作者头像
叔牙
发布2020-11-19 14:52:56
3980
发布2020-11-19 14:52:56
举报
文章被收录于专栏:一个执拗的后端搬砖工

先看一段简单的代码:

public static void main(String[] args) {

Integer a1 = 1;

Integer a2 = Integer.valueOf(1);

Integer a3 = new Integer(1);

System.out.println("a1 == a2 ? " + (a1 == a2));

System.out.println("a2 == a3 ?" + (a2 == a3));

Integer b1 = 127;

Integer b2 = Integer.valueOf(127);

Integer b3 = new Integer(127);

System.out.println("b1 == b2 ?" + (b1 == b2));

System.out.println("b2 == b3?" + (b2 == b3));

}

运行结果如下:

先介绍一个自动装箱拆箱概念,jdk1.5以后引入了自动拆装箱概念,目的是将原始类型值转自动地转换成对应的对象,其实相当于调用了Integer.valeOf()方法。上边的例子中自动装箱后的值和调用valueOf()得到的值相等并且指向相同的内存地址(==比较内存地址),而和new Integer()得到的值不相等,很明信new Integer()和调用其他类的构造器一样,会主动在内存中开辟一块空间存储响应的值,所以不满足和自动装箱和valueOf()得到的值指向相同的内存空间。

那么java中是如何做到所有的自动装箱和valueOf()指向的相同的对象呢?前边已经提到了,jdk1.5后引入了自动拆装箱,装箱动作等价于调用valueOf()方法,那么上述的问题可以转换为 如何保证多次调用valueOf()得到的是同一个Integer对象呢?

我们还是看一下Integer.valueOf()的源码:

public static Integer valueOf(String s, int radix) throws NumberFormatException {

return Integer.valueOf(parseInt(s,radix));

}

public static Integer valueOf(String s) throws NumberFormatException {

return Integer.valueOf(parseInt(s, 10));

}

public static Integer valueOf(int i) {

assert IntegerCache.high >= 127;

if (i >= IntegerCache.low && i <= IntegerCache.high)

return IntegerCache.cache[i + (-IntegerCache.low)];

return new Integer(i);

}

可以看到valueOf()有三个重载方法,从源码中可以看到,最终执行的是valueOf(int i)的实现。该方法的意思是,如果入参在IntegerCache.lowi 和IntegerCache.high之间,直接返回

IntegerCache.cache[i + (-IntegerCache.low)],否则创建一个Integer对象返回,这时候我们大概可以猜测到IntegerCache就是缓存了吧,当然猜测是不足以证明我们的议题,接着看一下IntegerCache到底是个什么鬼东西:

根据代码结构可以看到IntegerCache是Integer中的一个静态类,有一个私有构造器,对外暴露了三个属性,还有一个静态代码块,主要做的事情就是从虚拟机层面获取要缓存的Integer的最大值,然后创建了一个可以理解为长度是127-(-128) + 1的Integer数组,+1就是要缓存0,最后循环为数组赋值,最后cache[]中存放了-128~-1、0和1~127的数组。由于静态代码块是在类加载完后和初始化之前执行,所以在调用Integer的任何方法(包含构造器)之前,IntegerCache完成了加载且Integer cache[]完成了初始化,调用方法的时候根据需要能够使用数组中的缓存值。

再回到文章最开始的例子中,我们调用的Integer.value(1)和Integer.valueOf(127)其实都是从缓存中取得值,所以也就能够解释为什么a1==a2和b1 == b2了。

为了进一步理解Integer缓存,我们对上边的例子做一下延伸,修改后的代码如下:

运行代码会打印什么呢?我猜测是c1==c2?false,看一下运行结果:

可以看到,我们打印出了false,也就是说Integer.valueOf(256) != Integer.valueOf(256),为什么呢?我们再回顾一下Integer.valueOf()代码:

代码中IntegerCache.low=-128,IntegerCache.high=127,而我们的入参256很明显不在这个区间,这时候每次调用valueOf方法,都是新建一个Integer对象返回,这时候我们例子中的c1==c2等价于new Integer(256) == new Integer(256),显然不成立,返回false。

另外做一下扩展,IntegerCache.high这个值是跟虚拟机有关,正常情况下默认是127,但是如果我们想增大Integer缓存的区间,我们可以在jvm启动参数里边做手脚,如下图:

我们在jvm启动参数中加了-XX:AutoBoxCacheMax=512,意思就是讲Integer的缓存上边界改为512,我们重新运行实例看到如下运行结果:

可以看到,c1==c2打印了true,也就是说通过我们修改jvm启动参数后,IntegerCache中缓存的区间改成了[-128~512],当然我们多次调用valueOf(256)都是从缓存中取得同一个Integer对象。

以上是对jdk源码中Integer缓存做了一些分析,希望对各位带来帮助,如果有觉得分析不到位或者理解有偏差的,可以直接留言或者私聊我。介于本人公众号刚刚开通打赏功能,如果非要打赏,我也是不排斥的,哈哈!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2017-12-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 PersistentCoder 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档