说说JavaInteger缓存池是部分同学的盲区。着急的同学可以直接跳到结论查看结论。初学者可能很难阅读字节码验证和扩展链接。可以录下来以后可以等一段时间再看。介绍一个经典案例从一个经典案例开始publicclassIntegerCacheExample{publicstaticvoidmain(String[]args){Integera=127;整数b=127;System.out.printf("a==b:%s.\n",a==b);整数c=128;整数d=128;System.out.printf("c==d:%s.\n",c==d);}}简单的两个输出,思考五秒钟,检查答案。a==b:正确。c==d:错误。不知道答案是不是和你想的一样。下面说说为什么。整数缓存池IntegerCacheInteger缓存池?它是类似于字符串缓存池的东西吗?缓存池的名字是一个翻译,和字符串缓存池不一样。唯一的相似之处是池中确实存储了一些值。原文是IntegerCache,让我们去java.lang.Integer源码中一探究竟。我这篇文章看的源码是JDK1.8.0-openjdk的780行左右。我找到了内部类IntegerCache。先看注释(很多同学看源码不喜欢看??注释,大灰建议一定要先看注释!!!)缓存来支持对值之间自动装箱的对象标识语义JLS要求的-128和127(含)。缓存在第一次使用时初始化。缓存的大小可以由-XX:AutoBoxCacheMax=选项控制。VM初始化时,可能会设置java.lang.Integer.IntegerCache.high属性并保存在sun.misc.VM类的私有系统属性中。privatestaticclassIntegerCache{谷歌翻译解释如下:cachetosupportJLSrequirementsObject自动装箱值在-128到127之间的身份语义。缓存在第一次使用时被初始化。缓存的大小可以通过-XX:AutoBoxCacheMax=选项来控制。在VM初始化期间,可以设置java.lang.Integer.IntegerCache.high属性并将其存储在sun.misc.VM类的私有系统属性中。关键关键字:-128~127可以通过-XX:AutoBoxCacheMax来调整大小,可以解释缓存生成的范围是-128~127,启动前可以通过配置JVM参数AutoBoxCacheMax来修改参数。由此我们知道为什么a==b为真,c==d为假,因为a和b都是从缓冲池中取出来的,指向同一个指针,而c和d不是从缓冲池中取出来的,指向的是它们各自的内存地址。(如果不太明白什么是new对象指向新的内存地址,可以参考博主的内存文章,如果找不到,可能是内存文章还没写完,还没发布.)下面我们来验证一下这个结论是否正确IntegerCacheBytecodeVerification-这一段对于新手来说比较难读,但是不用细说也能轻松读懂。以后要看懂了,先从指针地址上查。运行下面的代码System.identityHashCode(Objectx)方法可以返回对象的内存地址,不管对象的类是否重写了hashCode()方法。System.out.printf("a:%s.\n",System.identityHashCode(a));System.out.printf("b:%s.\n",System.identityHashCode(b));System.out.printf("c:%s.\n",System.identityHashCode(c));System.out.printf("d:%s.\n",System.identityHashCode(d));输出如下:a:1118140819.b:1118140819.c:1975012498.d:1808253012。可以看到a,b指向同一个地址,c,d指向不同的地址。那我们就从字节码的角度来看一下JVM是如何做的。为了降低字节码的复杂度,我对比较部分的代码进行了注释publicclassIntegerCacheExample{publicstaticvoidmain(String[]args){Integera=127;整数b=127;//System.out.printf("a==b:%s.\n",a==b);整数c=128;整数d=128;//System.out.printf("c==d:%s.\n",c==d);}}生成字节码,在main方法类的目录下以命令行方式执行命令,会生成一个同名的.class文件javacIntegerCacheExample.java查看字节码javap-cIntegerCacheExample.classbytecode如下:从“IntegerCacheExample.java”编译publicclasscom.xh.basic.lang.integer.IntegerCacheExample{代码:0:aload_01:invokespecial#1//方法java/lang/Object."":()V4:returnpublicstaticvoidmain(java.lang.String[]);代码:0:bipush1272:invokestatic#2//方法java/lang/Integer.valueOf:(I)Ljava/lang/Integer;5:astore_16:bipush1278:invokestatic#2//方法java/lang/Integer.valueOf:(I)Ljava/lang/Integer;11:astore_212:sipush12815:invokestatic#2//方法java/lang/Integer.valueOf:(I)Ljava/lang/Integer;18:astore_319:sipush12822:invokestatic#2//方法java/lang/Integer.valueOf:(I)Ljava/lang/Integer;25:astore427:return}是不是看不懂,看不懂也不用着急。我不是万能的。让我们找到一些关键位置来解释。publicstaticvoidmain启动我们的主要代码。上面的部分可以自动忽略。我们只关注关键点。在main下的第2、8、15、22行,我们可以看到//Methodjava/lang/Integer.valueOf:(I)Ljava/lang/Integer可以猜到JAVA在运行时对Integerx做了如下优化调整=num;//优化为整数x=Integer.valueOf(num);我们按照源码去Integer.valueOf方法publicstaticIntegervalueOf(inti){if(i>=IntegerCache.low&&i<=IntegerCache.high)returnIntegerCache.cache[i+(-IntegerCache.low)];returnnewInteger(i);}源码告诉我们,在执行valueOf时,首先判断i是否在[low,high]范围内,如果在范围内,则从IntegerCache中取出,如果不在范围内,则进行newInteger(i)运算,即可得出结论。结论Integerx=num初始化时,如果num在-128~127范围内(默认范围),则从IntegerCache中获取值。这时,它会指向同一个指针地址。如果超出范围,则用newInteger运算,指向不同的指针。扩展一下,我们看到IntegerCache注释中提到了-XX:AutoBoxCacheMax。我们可以试试看有没有效果,改了之后有什么变化。我们在JVM运行参数中加入-XX:AutoBoxCacheMax=200。我正在使用想法。有些想法没有这个VM选项。我们在界面中选择Run-->EidtConfigurations-->Modifyoptions-->AddVM。添加选项后,您可以在界面上看到它们。可以添加运行参数Apply,运行代码查看效果AutoBoxCacheMax=200sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");该方法是获取VM参数中AutoBoxCacheMax的值publicclassIntegerCacheExample{publicstaticvoidmain(String[]args){System.out.printf("high:%s.\n",sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"));整数a=127;整数b=127;System.out.printf("a==b:%s.\n",a==b);整数c=128;整数d=128;System.out.printf("c==d:%s.\n",c==d);整数e=200;整数f=200;System.out.printf("e==f:%s.\n",e==f);整数g=201;整数h=201;System.out.printf("g==h:%s.\n",g==h);系统。out.printf("a:%s.\n",System.identityHashCode(a));小号system.out.printf("b:%s.\n",System.identityHashCode(b));System.out.printf("c:%s.\n",System.identityHashCode(c));系统。out.printf("d:%s.\n",System.identityHashCode(d));System.out.printf("e:%s.\n",System.identityHashCode(e));系统输出。printf("f:%s.\n",System.identityHashCode(f));System.out.printf("g:%s.\n",System.identityHashCode(g));System.out.printf("h:%s.\n",System.identityHashCode(h));}}结果输出如下:high:200.a==b:true.c==d:true.e==f:true.g==h:false.a:1118140819.b:1118140819.c:1975012498.d:1975012498.e:1808253012.f:1808253012.g:589431969.h:1252169911.可以看出200是从IntegerCache中取出来的,配置不同指针的newInteger生效。AutoBoxCacheMax=126从名字可以看出是Max值。如果小于127,是否有效?让我们测试一下。公共类IntegerCacheExampleMinValue{publicstaticvoidmain(String[]args){System.out.printf("high:%s.\n",sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"));整数a=127;整数b=127;System.out.printf("a==b:%s.\n",a==b);整数c=128;整数d=128;System.out.printf("c==d:%s.\n",c==d);整数min126a=126;整数min126b=126;System.out.printf("min126a==min126b:%s.\n",min126a==min126b);System.out.printf("a:%s.\n",System.identityHashCode(a));System.out.printf("b:%s.\n",System.identityHashCode(b));System.out.printf("c:%s.\n",System.identityHashCode(c));System.out.printf("d:%s.\n",System.identityHashCode(d));System.out.printf("min126a:%s.\n",System.identityHashCode(min126a));System.out.printf("min126b:%s.\n",System.identityHashCode(min126b));}}输出如下:high:126.a==b:true.c==d:false.min126a==min126b:true.a:697960108.b:697960108.c:943010986.d:1807837413.min126a:2066940133.min126b:2066940133.min126a==min126b可以,但是为什么a==b?此时缓存池126的值不是很高吗?那个127应该是新的?是不是配置没生效,还是127?其实并不是我们设置的没有生效。通过打印high的值,发现配置确实生效了,但是没有生效的原因是源码做了判断,贴出了IntegerCache中缓存池最大值的赋值方法。字符串integerCacheHighPropValue=sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");if(integerCacheHighPropValue!=null){try{inti=parseInt(integerCacheHighPropValue);i=Math.max(i,127);//最大数组大小为Integer.MAX_VALUEh=Math.min(i,Integer.MAX_VALUE-(-low)-1);}catch(NumberFormatExceptionnfe){//如果无法将属性解析为int,则忽略它。}}关键代码i=Math.max(i,127);可以看出,它判断了vm参数AutoBoxCacheMax和127的值,取最大值,也就是说,如果我们设置的AutoBoxCacheMax参数大于127,则不会生效。至此,我们的IntegerCahce文章就结束了。有不懂的朋友可以在文末给我留言,我会一一回复。扩展结论-XX:AutoBoxCacheMax设置可以修改缓存池的最大范围,但需要大于127才能生效。小于等于127时,仍取默认值127。最后,我是程序员大灰,一个还在努力的程序员。希望未来的你我都能不断学习成长。同时,不要失去快乐,做一个快乐的程序员。希望本文能给您带来收获。