为什么编译器/JVM不能让自动装箱“正常工作”?

2022-09-04 06:25:48

自动装箱是相当可怕的。虽然我完全理解之间的区别,但我不能不帮助有以下错误,地狱出我:==.equals

    final List<Integer> foo = Arrays.asList(1, 1000);
    final List<Integer> bar = Arrays.asList(1, 1000);
    System.out.println(foo.get(0) == bar.get(0));
    System.out.println(foo.get(1) == bar.get(1));

打印

true
false

他们为什么这样做?它与缓存的整数有关,但是如果是这种情况,为什么不直接缓存程序使用的所有整数呢?或者为什么JVM并不总是自动取消装箱到原始?

打印假假或真真会更好。

编辑

我不同意旧代码的破损。通过返回 true,您已经破解了代码。foo.get(0) == bar.get(0)

这不能在编译器级别通过在字节代码中用int替换Integer来解决(只要它从未被赋值为null)


答案 1
  • 他们为什么这样做?

-128 和 127 之间的每个整数都由 java 缓存。据说,他们这样做是为了提高性能。即使他们现在想回到这个决定上来,他们也不太可能这样做。如果有人根据这一点构建代码,他们的代码在被删除时会中断。对于业余爱好编码来说,这可能并不重要,但对于企业代码,人们会感到不安,诉讼也会发生。

  • 他们为什么不直接缓存程序使用的所有整数?

无法缓存所有整数,因为内存影响将是巨大的。

  • 为什么 JVM 不总是自动将框解包为基元?

因为JVM无法知道你想要什么。此外,此更改很容易破坏未为处理这种情况而构建的旧代码。

如果JVM在调用==时自动解装到原语,这个问题实际上会变得更加混乱。现在,您需要记住==始终比较对象引用,除非可以取消对对象的装箱。这将导致更多奇怪的令人困惑的情况,就像您上面提到的那样。

与其为此担心太久,不如记住这个规则:

切勿将对象与 == 进行比较,除非您打算通过引用来比较它们。如果你这样做,我想不出你会遇到问题的场景。


答案 2

你能想象如果每个人都带着高架进行拘留,性能会有多差吗?也不适用于 。Integernew Integer

Java语言(不是JVM问题)不能总是自动拆箱,因为为1.5之前的Java设计的代码应该仍然有效。