美文网首页
Integer陷阱

Integer陷阱

作者: heyong | 来源:发表于2017-12-04 17:05 被阅读47次

    概述

    今天同事遇到一个关于 Integer 的坑:有两个 Integer 对象,Integer i = 10000,Integer j = 10000,判断两个对象是否相等。Java里面基本类型都有对应的对象,并且回进行自动装箱和拆箱的操作,就误以为对象 i 和对象 j 是比较的整形值,但是结果确出乎意料。

    参考代码

    public class Test {
        public static void main(String[] args) {
            Integer a = 100;
            Integer b = 100;
    
            System.out.println(a == b);
            Integer i = 100001;
            Integer j = 100001;
    
            System.out.println(i == j);
        }
    }
    

    运行结果为:

    true
    false
    

    本以为输出结果应该是两个true,但是最终的答案出乎意料,于是查看编译以后Test类对应的字节码命令,字节码命令如下:

    javap -v Test.class
    

    得到的字节码命令如下:

    public static void main(java.lang.String[]);
        flags: ACC_PUBLIC, ACC_STATIC
        Code:
          stack=3, locals=5, args_size=1
             0: bipush        100
             2: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
             5: astore_1      
             6: bipush        100
             8: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
            11: astore_2      
            12: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
            15: aload_1       
            16: aload_2       
            17: if_acmpne     24
            20: iconst_1      
            21: goto          25
            24: iconst_0      
            25: invokevirtual #4                  // Method java/io/PrintStream.println:(Z)V
            28: ldc           #5                  // int 100001
            30: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
            33: astore_3      
            34: ldc           #5                  // int 100001
            36: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
            39: astore        4
            41: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
            44: aload_3       
            45: aload         4
            47: if_acmpne     54
            50: iconst_1      
            51: goto          55
            54: iconst_0      
            55: invokevirtual #4                  // Method java/io/PrintStream.println:(Z)V
            58: return        
    

    通过上面的字节码命令可以看出,Integer 的装箱是通过 invokestatic 指令,调用 Integer.valueOf() 方法实现的。对两个对象进行比较时,是通过 if_acmpne 指令比较两个Integer对象,接下来我们看看 Integer.valueOf() 的具体实现。

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

    IntegerCache.low = -128, IntegerCache.high = 127,在Integer中将 -128 到 127 对应的 Integer 对象缓存到 IntegerCache中,如果给 Integer对象赋值 >= -128 或者 赋值 <= 127,就从缓存中获取,如果超出了 -128 - 127的范围,就在堆中创建一个 Integer 对象,感兴趣的同学可以用 HSDB 工具查看。

    if_acmpne 指令会进行两个对象的比较,如果内存地址不一样就返回 false,这就解释了上面的情况,所以比较两个对象的时候还是调用equals方法靠谱

    相关文章

      网友评论

          本文标题:Integer陷阱

          本文链接:https://www.haomeiwen.com/subject/dspxixtx.html