Java学习篇之---小整数缓存机制

Java学习篇之---小整数缓存机制

这是一个有意思的话题。如果你运行如下代码:

Integer a = 1000, b = 1000;  
System.out.println(a == b);//1
Integer c = 100, d = 100;  
System.out.println(c == d);//2

你将会得到:

false
true


基本知识:

正如我们所知,如果两个引用指向同一个对象,按照“==”来判断两者是相等的。如果两个引用指向两个不同的对象,那么按照"=="来判断两者是不等的,即使两者有相同的引用内容。

因此最后一条语句也应该是false。

这就是有趣之处了。如果你去看Integer.java类,你会发现有一个内部私有类IntegerCache.java,它缓存了从-128~127之间的所有整数对象。
所以事情就是,所有的小整数都被在内部进行缓存。例如当我们声明如下:

Integer c = 100;
它实际上内部进行的操作是这样的:

Integer i = Integer.valueOf(100);
如果我们去看valueOf()方法,我们可以看到:

public static Integer valueOf(int i) {
      if (i >= IntegerCache.low && i
          return IntegerCache.cache[i + (-IntegerCache.low)];
      return new Integer(i);
}
如果值在-128~127之间,那么它就会从高速缓存中返回实例。

所以:

Integer c = 100, d = 100;
指向了同一个对象。

这就是为什么当我们写如下代码后我们获得true的原因:

System.out.println(c == d);
现在你可能会问,为什么这里需要缓存?

合理的解释是这样的:在此范围内的小整数比大整数使用率要高,所以为了减少潜在的内存占用,使用相同的底层对象是有价值的。

然而,通过反射API你会误用此功能。

运行起来,享受以下代码吧:

public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
      Class cache = Integer.class.getDeclaredClasses()[0]; //1
      Field myCache = cache.getDeclaredField("cache"); //2
      myCache.setAccessible(true);//3
      Integer[] newCache = (Integer[]) myCache.get(cache); //4
      newCache[132] = newCache[133]; //5
      int a = 2;
      int b = a + a;
      System.out.printf("%d + %d = %d", a, a, b); //
    }
运行结果:



对以上代码的解释:
正常情况下newCache[132]中存放的是4,newCache[133]中存放的是5,现在用newCache[133]中的值替换newCache[132]中的值。这样的话计算完毕之后发现结果是4,于是系统就会去默认应该缓存4的地址上取值,但是此时由于已经将原本是值4地址上的值换成了5,所以结果是5。

另外需要注意的是:

 System.out.printf("%d + %d = %d", a, a, b); //

System.out.println(a+" + "+a+" = "+b ); //

结果是不一样的。参考println的方法声明,作者对于不同的基本类型都提供了overwrite,而printf并没有为基本类型提供方法。

问题的本质在于:println(2+2)的结果仍是基本类型,并没有进行装箱,结果为4;System.out.println((Integer)2+2);的结果为5。

以上内容大部分翻译自:https://dzone.com/articles/why-1000-1000-returns-false-but-100-100-returns-tr

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值