有深意的代码(一段有意思代码学习Integer)

关于Integer ,作为int 包装类,新手经常会犯的错误是,比较两个Integer 用 ==,作为有经验的开发我们知道,包装类、String 都应用用equals方法进行判断。

在实际项目中,我们经常会有枚举值定义成Integer类型,有相当部分同学不注意,使用== 进行了比较,但是似乎又也没怎么出现Bug。这就不得不提起 Integer内部类 IntegerCache,它缓存了[-128,127] 的对象,这里使用了享元模式,避免了对象的重复创建。

因为枚举值数量通常比较小,在[-128,127] 之间,代码中也没有谁变态到 new Integer(value),所以,许多场景使用的是 IntegerCache 缓存的对象,所以== 没出现了问题。但不能说这么用没有错,程序员要严谨,以防后续用到数值超过缓存的范围,且不排除谁用new Integer 创建对象。

虽然IntegerCache 不对外暴露,但是Java反射,可是神通广大,如果用反射把一些缓存的值改掉,就会产生“有意思的”结果。下面代码大家觉得输出什么

Integer one = Integer.valueOf(1); Class iClass = Integer.class; Field valueField = iClass.getDeclaredField("value"); valueField.setAccessible(true); valueField.set(one,128); System.out.println((Integer)1 == 128);

有深意的代码(一段有意思代码学习Integer)(1)

输出true

其实这个涉及知识点不少,涉及Java 自动拆箱、Integer缓存

左边包装类 右边基本类型,会把左边拆卸为基本类型,由于它的value 已经被改为128了,所以输出true .

但是上述代码稍微修改下, 改为 Integer(1) == (Integer)128

Integer one = Integer.valueOf(1); Class iClass = Integer.class; Field valueField = iClass.getDeclaredField("value"); valueField.setAccessible(true); valueField.set(one,128); System.out.println((Integer)1 == (Integer)128);

有深意的代码(一段有意思代码学习Integer)(2)

结果就为false。

因为上面代码两个Integer 类型,比较是不是同一个对象,显然128不在缓存中,

如果把128 改为缓存范围内一个数呢,如下,结果也会为false。

public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException { Integer one = Integer.valueOf(1); Class iClass = Integer.class; Field valueField = iClass.getDeclaredField("value"); valueField.setAccessible(true); valueField.set(one,3); System.out.println((Integer)1 == (Integer)3); }

有深意的代码(一段有意思代码学习Integer)(3)

学C 的,估计第一次接触这个要吐血了,既然说了顺便复习下Integer 类型值默认null ,int 默认值0。这个IntgerCache 确实饶了点。

同样的Long 也有类似的Cache,值得一提的是redis 中有类似的缓存,只是范围不一样,编程复杂度与空间开销方面,如果是我会选择简单,期待jdk某个版本会把它干掉。

讲完,后面持续输出

,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。