问题

我刚刚看到类似这样的代码:

public class Scratch
{
    public static void main(String[] args)
    {
        Integer a = 1000, b = 1000;
        System.out.println(a == b);

        Integer c = 100, d = 100;
        System.out.println(c == d);
    }
}

运行时,这段代码将打印出来:

false
true

我理解为什么第一个是false:因为这两个对象是单独的对象,所以==比较引用。但我无法弄清楚,为什么第二个声明返回true?当Integer的值在一定范围内时,是否会出现一些奇怪的自动装箱规则?这里发生了什么?


#1 热门回答(90 赞)

trueline实际上是由语言规范保证的。 Fromsection 5.1.7

如果装箱的值为真,false,一个字节,范围为\ u0000到\ u007f的字符,或者介于-128和127之间的int或短号,则让r1和r2为任意两个装箱的结果p的转换始终是r1 == r2的情况。

讨论继续进行,建议虽然你的第二行产出是有保证的,但第一行却没有(参见下面引用的最后一段):

理想情况下,装箱给定的原始值p将始终产生相同的参考。实际上,使用现有的实现技术可能不可行。上述规则是务实的妥协。上面的最后一个条款要求将某些常见值装入无法区分的对象中。实现可以懒惰地或急切地缓存这些。对于其他值,此公式不允许对程序员的盒装值的身份进行任何假设。这将允许(但不要求)共享部分或全部这些引用。这确保了在大多数常见情况下,行为将是期望的行为,而不会造成过度的性能损失,尤其是在小型设备上。例如,较少内存限制的实现可以缓存所有字符和短路,以及-32K - 32K范围内的整数和长整数。


#2 热门回答(22 赞)

public class Scratch
{
   public static void main(String[] args)
    {
        Integer a = 1000, b = 1000;  //1
        System.out.println(a == b);

        Integer c = 100, d = 100;  //2
        System.out.println(c == d);
   }
}

输出:

false
true

是的,第一个输出产生用于比较参考; 'a'和'b' - 这是两个不同的参考。在第1点,实际上创建了两个类似于 - 的引用

Integer a = new Integer(1000);
Integer b = new Integer(1000);

产生的第二个输出是因为JVM以节省内存,当Integer在一个范围内(从-128到127)。在第2点,没有为'd'创建类型为Integer的新引用。它不是为Integer类型引用变量'd'创建新对象,而是仅使用'c'引用的先前创建的对象进行分配。所有这些都是由JVM完成的。

这些内存保存规则不仅适用于Integer。为了节省内存,以下包装器对象的两个实例(通过装箱创建)将始终为==,其原始值相同 -

  • 布尔值
  • 字节
  • 从\ u0000到\ u007f的字符(7f为十进制127)
  • 从-128到127的短整数

#3 热门回答(8 赞)

某些范围内的整数对象(我认为可能是-128到127)会被缓存并重新使用。该范围之外的整数每次都会获得一个新对象。


原文链接