Java 为什么可以';编译器/JVM是否只进行自动装箱;“只是工作”吗;?
自动装箱相当可怕。虽然我完全理解Java 为什么可以';编译器/JVM是否只进行自动装箱;“只是工作”吗;?,java,integer,autoboxing,caching,Java,Integer,Autoboxing,Caching,自动装箱相当可怕。虽然我完全理解==和.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.ge
==
和.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));
他们为什么这样做?这与缓存的整数有关,但如果是这样,为什么不缓存程序使用的所有整数呢?或者为什么JVM不总是自动取消绑定到原语
打印false false或true true会更好
编辑
我不同意旧代码的破坏。通过让foo.get(0)=bar.get(0)
返回true,您已经破坏了代码
在编译器级别,用字节码中的int替换Integer(只要它不被赋值为null)就可以解决这个问题。你能想象如果每个
整数都有内存开销,那么性能会有多差吗?也不适用于新整数
Java语言(不是JVM问题)不能总是自动取消装箱,因为为1.5版之前的Java设计的代码应该仍然可以工作。Integer
s在字节范围内是相同的对象,因为它们是缓存的<代码>整数
s不在字节范围之外。如果要缓存所有整数,请想象所需的内存
来自
所有这些魔术的结果是,您可以在很大程度上忽略int和Integer之间的区别,但需要注意一些事项。整数表达式可以有空值。如果您的程序尝试自动取消对null的绑定,它将抛出NullPointerException。==运算符对整型表达式执行引用标识比较,对整型表达式执行值相等比较。最后,即使装箱和拆箱是自动完成的,也存在与装箱和拆箱相关的性能成本
- 他们为什么这样做
- 他们为什么不缓存程序使用的所有整数呢
- 为什么JVM不总是自动取消绑定到原语
永远不要将对象与==进行比较,除非您打算通过引用对其进行比较。如果您这样做,我想不出会出现问题的场景。如果您完全跳过自动装箱,您仍然会遇到这种行为
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
最终列表foo=
asList(Integer.valueOf(1),Integer.valueOf(1000));
最终列表栏=
asList(Integer.valueOf(1),Integer.valueOf(1000));
System.out.println(foo.get(0)=bar.get(0));//真的
System.out.println(foo.get(1)=bar.get(1));//假的
如果您想要特定的行为,请更加明确:
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
最终列表foo=
asList(新整数(1),新整数(1000));
最终列表栏=
asList(新整数(1),新整数(1000));
System.out.println(foo.get(0)=bar.get(0));//假的
System.out.println(foo.get(1)=bar.get(1));//假的
这就是Eclipse在默认情况下将自动装箱作为警告的原因。很多人都有这个问题,甚至是写Java书籍的人 在下面的几英寸中,作者讨论了在IdentityHashMap中使用自动装箱整数作为键的问题。他在WeakHashMap中使用自动装箱整数键。他使用的示例值大于128,因此他的垃圾收集调用成功。如果有人使用他的示例并使用小于128的值,那么他的示例将失败(因为密钥被永久缓存)。当您编写
foo.get(0)
编译器与您如何创建列表无关。它只查看列表foo的编译时类型。所以,如果这是一个列表,它会将其视为一个列表,就像它应该做的那样,并且列表的get()总是返回一个整数。如果要使用==则必须编写
System.out.println(foo.get(0).intValue() == bar.get(0).intValue());
不是
因为它有完全不同的含义。它只是起作用而已!!但不是你所期望的;)实际上,您的示例与自动装箱几乎没有关系,这种行为早于自动装箱。的确,自动装箱迫使我们更加注意它:equals()是比较对象的(通常是正确的)方式,==是比较基本体的(唯一的)方式。。。自动装箱帮助程序员(几乎)互换地处理整数和整数。。。这可能是由于特殊性造成的,这些特殊性也会影响字符串的实例。据我所知,根据价值,在幕后发生了一些合并。这可以通过使用
new
关键字来防止。如果您使用的是Eclipse,则可以在这些情况下启用编译器警告:“首选项>Java>编译器>错误/警告”中的“装箱和取消装箱转换”。也许在其他IDE中也有类似的警告,但遗憾的是,当从命令行编译时,这是不可用的。我认为您的代码要被窃听,而不是Javac和JVM的问题。见下面@alexander pogrebnyak的回复。我同意这里有些混乱和混乱
System.out.println(foo.get(0).intValue() == bar.get(0).intValue());
System.out.println(foo.get(0) == bar.get(0));