【问题标题】:Integer i=3 vs Integer i= new Integer (3) [duplicate]整数 i = 3 与整数 i = 新整数(3)[重复]
【发布时间】:2013-07-05 17:32:18
【问题描述】:

我正在比较两段代码。首先

Integer i=3;
Integer j=3;
if(i==j)
   System.out.println("i==j");  //prints i==j              

第二,

Integer i=3;
Integer j=new Integer(3);
if(i==j)
   System.out.println("i==j"); // does not print

我怀疑在第一个 sn-p 中为什么要打印i==j?引用不应该不同吗?

【问题讨论】:

  • 与reference、new、Objects、比较内存地址有关#Idk #CIS20...Somthing
  • == 在分配时比较引用而不是值。在第一种情况下,ij 都指向内存中的相同整数。在第二种情况下,使用 new 创建两个具有相同值 3 的对象整数的新实例。
  • 这不是链接问题的副本。请注意,由于 new Integer(1) == new Integer(1) 的错误前提,该问题被关闭为“不是一个真正的问题”,这是不正确的。
  • @JohnKugelman - 这是同一个问题,只是颠倒了,该问题的答案涵盖了。
  • @AMR:不,根本不是这样。

标签: java


【解决方案1】:

我怀疑在第一个 sn-p 中为什么要打印 i==j ? 引用不应该不同吗?

因为,

    Integer i=3;
    Integer j=3;

在内部使用 Integer#valueOf() 来执行 autoBoxing 。 oracle doc 提到了valueOf() 方法:

返回一个表示指定 int 值的 Integer 实例。如果一个 new Integer 实例不是必须的,这个方法一般应该是 优先于构造函数 Integer(int) 使用,因为此方法是 可能会产生明显更好的空间和时间性能 缓存经常请求的值。 这个方法会一直缓存 -128 到 127(含)范围内的值,并且可以缓存其他值 超出此范围。

由于值3 被缓存,因此变量ij 都引用同一个对象。所以,i==j 正在返回 trueInteger#valueOf() 使用 flyweight pattern

【讨论】:

    【解决方案2】:
    Integer i=3;
    Integer j=3;
    if(i==j)System.out.println("i==j");
    

    在这里,3 被自动装箱,因此 ij 指向同一个 Integer

    Integer i=3;
    Integer j=new Integer(3);
    if(i==j)System.out.println("i==j"); // does not print
    

    这里,i 指向自动装箱的Integer,而j 指向新的Integer,因此引用未通过等于== 运算符测试。

    但是,这里还有一些值得深思的地方。

    Integer i=300;
    Integer j=300;
    if(i!=j)System.out.println("i!=j"); // prints i!=j
    

    为什么?因为,自动装箱仅在 -128 到 127 之间共享 Integer 实例。但是,这种行为在不同的 Java 实现之间可能会有所不同。

    【讨论】:

    • Integer 的池不是由 JVM 完成的。完全由Integer 完成。查看Integer的源代码。
    • @SteveKuo 我刚刚检查了Integer.valueOf(),是的,范围以Integer 为界,介于-128 到IntegerCache.high (127) 之间。我已经更正了我的答案。谢谢。
    【解决方案3】:

    Java 池化介于 -128 和 127 之间的整数,因此两个引用是相同的。

    Integer i=3;
    Integer j=3;
    

    这会导致自动装箱,并且 3 被转换为整数 3。因此,对于 i 指的是常量池中的 Integer 对象,现在当您执行 j=3 时,与 i 的引用相同的引用被分配给 j。

    而下面的代码:

    Integer j=new Integer(3);
    

    总是在堆中创建一个新的整数。这不是汇集的。因此,您会看到两个引用都指向不同的对象。结果是

    Integer i=3;
    Integer j=new Integer(3);
    if(i==j)
       System.out.println("i==j"); // **does not print**
    

    【讨论】:

    • ...在第一种情况下。
    【解决方案4】:

    这与拳击的工作方式有关。来自JLS section 5.1.7

    如果被装箱的值 p 是真、假、一个字节或 \u0000 到 \u007f 范围内的一个字符,或者一个介于 -128 和 127(含)之间的 int 或短数字,则令 r1 和 r2 为p 的任意两次装箱转换的结果。 r1 == r2 总是如此。

    基本上,Java 实现必须为适当的小值缓存装箱表示,并且可能缓存更多。 == 运算符只是比较引用,因此它专门检测两个变量是否引用同一个对象。在第二个代码 sn-p 中,它们肯定不会,因为 new Integer(3) 肯定与以前创建的引用不同......它总是创建一个新对象。

    由于上述规则,这段代码必须始终给出相同的结果:

    Integer x = 127;
    Integer y = 127;
    System.out.println(x == y); // Guarantee to print true
    

    而这可能是两种方式:

    Integer x = 128;
    Integer y = 128;
    System.out.println(x == y); // Might print true, might print false
    

    【讨论】:

    • 你应该解释一下==比较。
    • @William Morrison:不同意。 OP 显然已经知道 == 是引用相等。问题是他错误地认为引用是不同的(也就是说,这里缺少的概念是一些原语的“实习”,而不是摸索==)。
    • 我没有惹任何人。也许我错了。我更喜欢过度详尽的解释...
    • @WilliamMorrison 所以,根据你的说法,每个解释都应该以:“一开始,有一个词......”
    • 如果 Jon Skeet 回答你的问题,你只需要说声谢谢,因为肯定是正确的,不要说“你应该......”哈哈
    【解决方案5】:

    不应该,因为 java 可以在自动装箱时将预制的 Integer 对象用于小数字。

    【讨论】:

      【解决方案6】:

      因为在第二段代码中,您的第一个整数被自动装箱,而第二个不是。

      这意味着正在动态创建一个新的 Integer 实例。这两个对象实例是不同的。相等性检查将在那里返回 false,因为这两个实例实际上是不同的内存。

      【讨论】:

      • 不,这是在这两种情况下都使用自动装箱的第一段代码;第二个仅将其用于第一个值。
      • 我指的是第一个整数,而不是第二个。
      • 那是非常不清楚的。从这个答案中仍然不清楚为什么第一段代码会打印“i==j”,因为您没有解释任何有关装箱的缓存性质的内容。
      • 是的,我想还不清楚。我同意忽略对自动装箱的充分解释。你的好多了。
      【解决方案7】:

      解释器/JIT 优化器可以将所有 3 放在同一个框中。但如果你强制一个“新”,那么你会得到另一个地址。

      试试

       j=8; // after initialization of i and j
      

      然后看到 j 的地址更改为第一个版本。

      【讨论】:

        【解决方案8】:

        在使用自动装箱时,与字符串类似的方式,例如在

        Integer i = 3;
        Integer j = 3;
        

        Java 可以从预制对象池中提取。在j 的情况下,池中已经有一个Integer 实例代表3 的值,因此它从中提取。因此,ij 指向同一事物,因此 i == j

        在第二个示例中,您为j 显式实例化了一个新的Integer 对象,因此ij 指向不同的对象,因此i != j

        【讨论】:

          【解决方案9】:

          在以下代码中:

          Integer i=3;
          Integer j=3;
          if(i==j)
             System.out.println("i==j");
          

          这里,“==”比较的是引用而不是值。 所以,整数 i 和 j 都指向内存中的同一个引用。

          在下面的代码中:

          Integer i=3;
          Integer j=new Integer(3);
          if(i==j)
             System.out.println("i==j");
          

          对两个值的引用都发生了变化,因为“j”是内存中新创建的整数对象/引用,而“i”只是引用一个值。

          因此,第一个代码的输出是“i==j”,第二个代码没有任何输出。

          希望这会有所帮助。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2019-02-07
            • 2020-04-28
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-05-11
            相关资源
            最近更新 更多