Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/323.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么可以';编译器/JVM是否只进行自动装箱;“只是工作”吗;?_Java_Integer_Autoboxing_Caching - Fatal编程技术网

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。==运算符对整型表达式执行引用标识比较,对整型表达式执行值相等比较。最后,即使装箱和拆箱是自动完成的,也存在与装箱和拆箱相关的性能成本

  • 他们为什么这样做
-128和127之间的每个整数都由java缓存。据说,他们这样做是为了提高性能。即使他们现在想推翻这一决定,也不太可能。如果有人以此为基础构建代码,那么当代码被取出时,他们的代码就会中断。对于爱好编码来说,这也许并不重要,但对于企业代码来说,人们会感到不安,并会发生诉讼

  • 他们为什么不缓存程序使用的所有整数呢
所有整数都不能被缓存,因为内存将是巨大的

  • 为什么JVM不总是自动取消绑定到原语
因为JVM无法知道您想要什么。此外,此更改可能很容易破坏未构建用于处理此情况的遗留代码

如果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));