我刚刚看到与此类似的代码:

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?当整数的价值在一定范围内时,是否有一些奇怪的自动氧化规则?这里发生了什么?

有帮助吗?

解决方案

true 实际上,语言规范可以保证行。从 第5.1.7节:

如果被装箱的值p是正确的,则为false,一个字节,范围 u0000至 u007f的字符,或-128和127之间的int或短数字,然后让R1和R2为任何两个拳击转换的结果p。 R1 == R2总是如此。

讨论继续进行,表明尽管您的第二行产出可以保证,但第一个不是(请参阅下面引用的最后一段):

理想情况下,给定的原始值P拳击始终会产生相同的参考。实际上,使用现有的实施技术可能是不可行的。上面的规则是务实的妥协。上面的最终条款要求将某些共同值始终被包装到难以区分的对象中。实施可能会懒洋洋或热切地缓存。

对于其他值,此公式将不允许对程序员部分上盒装值的身份进行任何假设。这将允许(但不需要)共享某些或全部这些参考。

这样可以确保在大多数常见的情况下,行为将是所需的行为,而不会施加不适当的性能处罚,尤其是在小型设备上。较少的内存限制实现可能会例如缓存所有字符和短裤,以及整数和longs -32k- +32k的范围。

其他提示

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”创建类型整数的新引用。它不是为整数类型引用变量“ d”创建新对象,而仅以“ C”引用的先前创建的对象分配。所有这些都是由 JVM.

这些内存保存规则不仅适用于整数。为了保存内存的目的,以下包装对象的两个实例(在通过拳击创建)中始终为==,其中其原始值相同 -

  • 布尔
  • 字节
  • 角色来自 u0000\u007f (7F为127个小数)
  • 短而整数 -128127

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

是的,当值在一定范围内时,有一个奇怪的自动氧化规则。当您将常数分配给对象变量时,语言定义中的任何内容都没有说明新对象 必须 被创建。它可以从缓存重复使用现有对象。

实际上,JVM通常为此目的存储一个小整数的缓存,以及诸如boolean.true和boolean.false之类的值。

这是一个有趣的观点。在书里 有效的Java 建议始终覆盖自己的课程。同样,要检查Java类的两个对象实例的平等始终使用Equals方法。

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

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

返回:

true
true

我的猜测是,Java保留了已经被“盒装”的小整数的缓存,因为它们非常普遍,并且节省了很多时间来重新使用现有对象,而不是创建新对象。

在Java中,拳击在-128至127之间,用于整数。当您使用此范围内的数字时,您可以将其与==运算符进行比较。对于超出范围之外的整数对象,您必须使用平等对象。

直接分配INT字面的文字为整数参考是自动盒的一个示例,其中编译器对对象转换代码进行了文字值。

因此,在编译阶段编译器中转换 Integer a = 1000, b = 1000;Integer a = Integer.valueOf(1000), b = Integer.valueOf(1000);.

就是这样 Integer.valueOf() 实际上给我们整数对象的方法,如果我们查看 Integer.valueOf() 方法我们可以清楚地看到-128至127(包含)范围内的方法缓存整数。

/**
 *
 * This method will always cache values in the range -128 to 127,
 * inclusive, and may cache other values outside of this range.
 *
 * @param  i an {@code int} value.
 * @return an {@code Integer} instance representing {@code i}.
 * @since  1.5
 */
 public static Integer valueOf(int i) {
     if (i >= IntegerCache.low && i <= IntegerCache.high)
         return IntegerCache.cache[i + (-IntegerCache.low)];
     return new Integer(i);
 }

因此,而不是创建和返回新的整数对象,而是 Integer.valueOf() 该方法从内部返回整数对象 IntegerCache 如果通过的INT字面意思大于-128,小于127。

Java缓存了这些整数对象,因为此范围的整数在日常编程中被大量使用,从而间接节省了一些内存。

由于静态块将类加载到内存中时,该缓存是在第一次使用时初始化的。缓存的最大范围可以由 -XX:AutoBoxCacheMax JVM选项。

这种缓存行为不适用于整数对象,类似于Integer.integercache我们也有 ByteCache, ShortCache, LongCache, CharacterCache 为了 Byte, Short, Long, Character 分别。

您可以在我的文章中阅读更多 Java Integer Cache-为什么Integer.valueof(127)== Integer.valueof(127)为true.

在Java 5中,引入了一项新功能,以节省内存并提高整数类型对象处理的性能。整数对象在内部缓存,并通过相同的引用对象重复使用。

  1. 这适用于–127至+127(最大整数值)之间的整数值。

  2. 此整数缓存仅适用于自动氧化。使用构造函数构建整数对象将不会缓存。

有关更多详细信息,请通过以下链接:

整数缓存详细

如果我们检查 Integer obeject,我们将找到 valueOf 像这样的方法:

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

这可以解释为什么 Integer 对象,范围为-128(Integer.low)至127(Integer.high),在自动氧化过程中是相同的引用对象。我们可以看到有一堂课 IntegerCache 照顾 Integer 缓存数组,这是一个私人静态内部类 Integer 班级。

还有另一个有趣的例子可以帮助我们理解这种奇怪的情况:

public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {

      Class cache = Integer.class.getDeclaredClasses()[0]; 
      Field myCache = cache.getDeclaredField("cache"); 
      myCache.setAccessible(true);

      Integer[] newCache = (Integer[]) myCache.get(cache); 
      newCache[132] = newCache[133]; 

      Integer a = 2;
      Integer b = a + a;
      System.out.printf("%d + %d = %d", a, a, b); //The output is: 2 + 2 = 5    

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