自动装箱相当可怕。虽然我完全理解之间的区别 ==.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 不总是自动拆箱为原始类型?

打印 false false 或 true true 会更好。

编辑

我不同意破坏旧代码。有了 foo.get(0) == bar.get(0) 返回 true 你已经破坏了代码。

难道不能在编译器级别通过在字节代码中用 int 替换 Integer 来解决这个问题吗(只要它永远不会被分配为 null)

有帮助吗?

解决方案

  • 他们为什么要这样做?

-128 到 127 之间的每个整数都由 java 缓存。据推测,他们这样做是为了提高性能。即使他们现在想反悔这个决定,他们也不太可能会这么做。如果有人根据此构建代码,那么当它被删除时,他们的代码就会崩溃。对于业余编码来说,这也许并不重要,但对于企业代码来说,人们会感到不安,并且会发生诉讼。

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

所有整数都不能被缓存,因为内存影响将是巨大的。

  • 为什么 JVM 不总是自动拆箱为原始类型?

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

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

与其太担心这个问题,不如记住这条规则:

绝不 使用 == 比较对象,除非您打算通过引用来比较它们。如果您这样做,我无法想象您会遇到问题的情况。

其他提示

你能想象的表现多么糟糕是,如果每Integer对拘留的开销进行?也不起作用为new Integer

在Java语言(不是一个JVM问题)不能总是自动拆箱,因为程序设计时,预先1.5 Java的应该仍然工作。

在字节范围Integers是同一个对象,因为它们被缓存。字节范围以外Integers不是。如果所有整数将被高速缓存的,想象所需的内存。

和从此处

  

这一切神奇的结果是,你可以在很大程度上忽略int和整数之间的区别,有几个注意事项。整数表达式可以具有一个空值。如果你的程序试图autounbox空,它会抛出一个NullPointerException。关于INT表达式整数表达式和数值相等比较==运算符执行参考同一性比较。最后,还有与装箱和拆箱相关的性能开销,即使是自动完成的。

如果你跳过自动装箱完全,你仍然可以得到这个行为。

final List<Integer> foo =
  Arrays.asList(Integer.valueOf( 1 ), Integer.valueOf( 1000 ));
final List<Integer> bar =
  Arrays.asList(Integer.valueOf( 1 ), Integer.valueOf( 1000 ));

System.out.println(foo.get(0) == bar.get(0)); // true
System.out.println(foo.get(1) == bar.get(1)); // false

如果你想有一个特定的行为更加明确:

final List<Integer> foo =
  Arrays.asList( new Integer( 1 ), new Integer( 1000 ));
final List<Integer> bar =
  Arrays.asList( new Integer( 1 ), new Integer( 1000 ));

System.out.println(foo.get(0) == bar.get(0)); // false
System.out.println(foo.get(1) == bar.get(1)); // false

这是有原因的,为什么Eclipse已经自动装箱作为默认的警告。

很多人都对这个问题有疑问,甚至是写 Java 书籍的人。

专业Java编程, 就在下面几英寸处,作者讨论了使用自动装箱的整数作为 IdentityHashMap 中的键的问题,他在 WeakHashMap 中使用了自动装箱的整数键。他使用的示例值大于 128,因此他的垃圾收集调用成功。如果有人使用他的示例并使用小于 128 的值,他的示例将会失败(由于密钥被永久缓存)。

当你写

foo.get(0)

编译器不要紧,你是如何创建的列表。它不仅外观在列表foo的编译时类型。所以,如果这是一个List 的,它将把它看成一个List 的,因为这是应该做的,并且是List 的获得()总是返回一个整数。如果你想使用==那么你必须写

System.out.println(foo.get(0).intValue() == bar.get(0).intValue());

System.out.println(foo.get(0) == bar.get(0));

,因为其具有一个完全不同的含义。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top