【问题标题】:Why equal operator works for Integer value until 128 number? [duplicate]为什么相等运算符适用于整数值直到 128 数字? [复制]
【发布时间】:2013-02-22 13:04:16
【问题描述】:

为什么整数 == 运算符不适用于 128 和整数值之后?有人能解释一下这种情况吗?

这是我的 Java 环境:

java version "1.6.0_37"
Java(TM) SE Runtime Environment (build 1.6.0_37-b06)
Java HotSpot(TM) 64-Bit Server VM (build 20.12-b01, mixed mode)

示例代码:

Integer a;
Integer b;
a = 129;
b = 129;

for (int i = 0; i < 200; i++) {
    a = i;
    b = i;

    if (a != b) {
        System.out.println("Value:" + i + " - Different values");
    } else {
        System.out.println("Value:" + i + " - Same values");
    }
}

部分控制台输出:

Value:124 - Same values
Value:125 - Same values
Value:126 - Same values
Value:127 - Same values
Value:128 - Different values
Value:129 - Different values
Value:130 - Different values
Value:131 - Different values
Value:132 - Different values

【问题讨论】:

    标签: java integer equals-operator


    【解决方案1】:

    查看the source code of Integer。您可以在那里看到值的缓存。

    缓存仅在您使用Integer.valueOf(int) 时发生,而不是在您使用new Integer(int) 时发生。您使用的自动装箱使用Integer.valueOf

    根据JLS,您始终可以相信,对于介于 -128 和 127 之间的值,在自动装箱后您会获得相同的 Integer 对象,并且在某些实现中,即使对于更高的值,您也可能会获得相同的对象。

    实际上在 Java 7 中(我认为在 Java 6 的较新版本中),IntegerCache 类的implementation 发生了变化,上限不再是硬编码,但可以通过属性“java.lang”进行配置.Integer.IntegerCache.high”,因此如果您使用 VM 参数 -Djava.lang.Integer.IntegerCache.high=1000 运行程序,您将获得所有值的“相同值”。

    但是 JLS 仍然保证它只到 127:

    理想情况下,装箱一个给定的原始值 p,总是会产生一个相同的引用。在实践中,使用现有的实现技术这可能是不可行的。上述规则是一种务实的妥协。上面的最后一个条款要求某些常见的值总是被装箱到无法区分的对象中。实现可能会延迟或急切地缓存这些内容。

    对于其他值,此公式不允许程序员对装箱值的身份进行任何假设。这将允许(但不要求)共享部分或全部这些引用。

    这可确保在最常见的情况下,行为将是期望的行为,而不会造成过度的性能损失,尤其是在小型设备上。例如,内存限制较少的实现可能会缓存所有字符和短整数,以及 -32K - +32K 范围内的整数和长整数。

    【讨论】:

      【解决方案2】:

      Integerint 的包装类。

      Integer != Integer 比较实际的对象引用,int != int 将比较值。

      如前所述,值 -128 到 127 被缓存,因此为这些值返回相同的对象。

      如果超出该范围,将创建单独的对象,因此引用将不同。

      修复它:

      • 将类型设为int
      • 将类型转换为int
      • 使用.equals()

      【讨论】:

        【解决方案3】:

        根据 Java 语言规范:

        如果被装箱的值p是真,假,一个字节,一个字符在范围内 \u0000 到 \u007f,或者一个介于 -128 和 127 之间的整数或短数字,然后 设 r1 和 r2 是 p 的任意两次装箱转换的结果。这是 总是 r1 == r2。

        JLS Boxing Conversions

        Refer to this article for more information on int caching

        【讨论】:

        • 这个答案是错误的,和热点jvm无关,缓存是在Integer的源码中实现的,
        • @lbalazscs 据我所知,缓存的值依赖于 jvm。我认为这个缓存是在java语言规范中指定的,但是没有指定要缓存的值。这就是我提到热点jvm的原因。这不正确吗?
        • 不正确。不如你看看java.lang.Integer的源码吧,比如
        • 不正确,与java.lang.Integer的实现有关
        • Integer.valueOf(和 not JLS)的文档提到此方法可以使用缓存。
        【解决方案4】:

        Integer 对象具有内部缓存机制:

        private static class IntegerCache {
            static final int high;
            static final Integer cache[];
        
            static {
                final int low = -128;
        
                // high value may be configured by property
                int h = 127;
                if (integerCacheHighPropValue != null) {
                    // Use Long.decode here to avoid invoking methods that
                    // require Integer's autoboxing cache to be initialized
                    int i = Long.decode(integerCacheHighPropValue).intValue();
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - -low);
                }
                high = h;
        
                cache = new Integer[(high - low) + 1];
                int j = low;
                for(int k = 0; k < cache.length; k++)
                    cache[k] = new Integer(j++);
            }
        
            private IntegerCache() {}
        }
        

        另见 valueOf 方法:

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

        这就是为什么您应该使用valueOf 而不是new Integer。自动装箱使用此缓存。

        另请参阅此帖子:https://effective-java.com/2010/01/java-performance-tuning-with-maximizing-integer-valueofint/

        使用== 不是一个好主意,使用等于来比较值。

        【讨论】:

          【解决方案5】:

          使用.equals() 代替==

          仅对介于 -127 和 128 之间的数字缓存整数值,因为它们最常使用。

          if (a.equals(b)) { ... }
          

          【讨论】:

            【解决方案6】:

            根据您获取Integer 实例的方式,它可能对任何值都不起作用:

            System.out.println(new Integer(1) == new Integer(1));
            

            打印

            false
            

            这是因为应用于引用类型操作数的== 运算符与这些操作数所代表的值无关。

            【讨论】:

              【解决方案7】:

              这是因为Integer 类的实现逻辑。它已经为数字准备了对象,直到 128。例如,您可以查看 http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/Integer.java 的 open-jdk 源(搜索缓存 [])。
              基本上不应该使用== 来比较对象,除了枚举之外。

              【讨论】:

                猜你喜欢
                • 2013-02-08
                • 1970-01-01
                • 1970-01-01
                • 2012-12-07
                • 2016-09-29
                • 2023-04-08
                • 2018-07-30
                • 2018-04-03
                相关资源
                最近更新 更多