一尘不染

为什么没有在Java中缓存Integer?

java

我知道在该主题上也有类似的帖子,但是它们并没有完全解决我的问题。当您这样做时:

Integer a = 10;
Integer b = 10;
System.out.println("a == b: " + (a == b));

(显然)true大多数时间都会打印,因为以某种方式缓存了[-128,127]范围内的整数。但:

Integer a = new Integer(10);
Integer b = new Integer(10);
System.out.println("a == b: " + (a == b));

会回来的false。我知道我正在请求一个Integer的新实例,但是由于装箱的原语在Java中是不可变的,并且已经有了执行“正确的事情”的机制(如第一种情况所示),为什么会发生这种情况?

如果Integer的所有实例(具有10)都在内存中是同一对象,这是否更有意义?换句话说,为什么我们没有类似于“字符串实习”的“整数实习”?

更好的是,如果代表盒装基元的实例代表相同事物( 无论其值(和类型)如何) 是同一对象,这是否更有意义?或至少正确回应==


阅读 229

收藏
2020-09-09

共1个答案

一尘不染

非常清楚的是,缓存会对性能造成不可接受的影响–每次创建Integer时,都会产生额外的if语句和内存查找。仅此一个因素就掩盖了任何其他原因,而使该线程感到痛苦的其余部分。

就“正确”响应==而言,OP在其正确性假设中是错误的。整数确实通过Java社区对正确性的期望,当然也通过规范对正确性的定义,对==做出正确的响应。也就是说,如果两个引用指向同一对象,则它们为==。如果两个引用指向
不同的 对象,即使它们具有相同的内容,它们 也不 ==是相同的。因此,得出的结果就不足为奇new Integer(5) == newInteger(5)false

更为有趣的问题是, 为什么 new Object();每次都需要创建一个唯一的实例?即为什么newObject();不允许缓存?答案是wait(...)notify(...)。缓存new Object()s会错误地导致线程在不应该同步时彼此同步。

如果不是那样的话,那么Java实现可以完全new Object()单例缓存s。

new Integer(5)这就说明了为什么必须创建7个唯一的Integer对象(每个对象都包含值5
)需要完成7次(因为Integerextend Object)。


次要的,不太重要的东西: 自动装箱和自动拆箱功能导致本来不错的方案中的一个问题。没有该功能,您将无法进行比较new Integer(5) == 5。要启用这些功能,Java 会将 对象 取消装箱 (并且 不对 原语进行装箱)。因此new Integer(5) == 5被转换为:(new Integer(5).intValue() == 5不是 new Integer(5) == newInteger(5)

最后一两件事要了解是那个自动装箱n 被做new Integer(n)。通过内部调用来完成Integer.valueOf(n)

如果您认为自己了解并想要测试自己,请预测以下程序的输出:

public class Foo {
  public static void main (String[] args) {
    System.out.println(Integer.valueOf(5000) == Integer.valueOf(5000));
    System.out.println(Integer.valueOf(5000) == new Integer(5000));
    System.out.println(Integer.valueOf(5000) == 5000);
    System.out.println(new Integer(5000) == Integer.valueOf(5000));
    System.out.println(new Integer(5000) == new Integer(5000));
    System.out.println(new Integer(5000) == 5000);
    System.out.println(5000 == Integer.valueOf(5000));
    System.out.println(5000 == new Integer(5000));
    System.out.println(5000 == 5000);
    System.out.println("=====");
    System.out.println(Integer.valueOf(5) == Integer.valueOf(5));
    System.out.println(Integer.valueOf(5) == new Integer(5));
    System.out.println(Integer.valueOf(5) == 5);
    System.out.println(new Integer(5) == Integer.valueOf(5));
    System.out.println(new Integer(5) == new Integer(5));
    System.out.println(new Integer(5) == 5);
    System.out.println(5 == Integer.valueOf(5));
    System.out.println(5 == new Integer(5));
    System.out.println(5 == 5);
    System.out.println("=====");
    test(5000, 5000);
    test(5, 5);
  }
  public static void test (Integer a, Integer b) {
    System.out.println(a == b);
  }
}

为了获得额外的信用,如果所有值==都更改为,还可以预测输出.equals(...)

更新: 感谢用户@sactiw的评论:“缓存的默认范围是-128到127,并且从Java 1.6开始,您可以通过从命令行传递-
XX:AutoBoxCacheMax =来重置上限值> = 127”

2020-09-09