栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

integer使用==比较大小引发的线上问题记录

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

integer使用==比较大小引发的线上问题记录

    记录一个线上反馈出的问题,虽然问题解决了,但是反应出的问题是基本的代码规范问题,希望对遇到此类问题或现在对此问题存在认知误区的同学有所帮助和警示。
    简单描述一下场景:课程需要与会员卡进行关联,课程详情页面需要显示所有的会员卡信息,并将已关联的会员卡进行选中设置。设置是否选中的逻辑是嵌套遍历所有会员卡列表和数据库记录课程已关联的会员卡列表,如果两个会员卡id相同则进行设置选中标识。
    项目中使用的是 == 进行比较两个会员卡id是否相同。项目上线之后运行正常,过一段时间之后反馈出的问题是新增课程关联的会员卡信息时,明明已经勾选会员卡,但是保存成功之后还是显示未选中的状态。
问题定位:
    对于字符串类型的数值比较大部分人都会使用equals,毕竟是比较的是内容非地址值。而==就不一样了,如果是对于基本数据类型,==比较的是数值是否相等非地址值,但是对于包装类型(也属于引用类型)比较的就是地址值。所以这个问题处理方式很简单,第一种方式就是将会员卡的数据类型修改为int(项目中的会员卡id定义的原数据类型为integer),还是使用==进行比较;另一种方式使用equals进行比较(会员卡数据类型不变还是integer)。
    代码验证上面的处理方案:
示例代码:

 public static void main(String[] args) {
        Integer a = 100;
        Integer b = 100;
        System.out.println(a == b);  // true
        Integer a1 = 127;
        Integer b1 = 127;
        System.out.println(a1 == b1);  // true
        Integer a2 = 128;
        Integer b2 = 128;
        System.out.println(a2 == b2);  // false
        Integer c = 143;
        Integer d = 143;
        System.out.println(c == d);  // false
        System.out.println(c.equals(d));  // true
        int e = 256;
        int f = 256;
        System.out.println(e == f);   // true
    }

    说一下为什么可以使用equals进行Integer类型比较数值大小:
Integer中equals方法源码:

 public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }

Integer中intValue方法源码:

  public int intValue() {
        return value;
    }

    也就是说Integer中的equals最终还是将Integer转化成int进行比较数值大小。
    继续回答为什么使用==进行数据比较大小,上线一段时间之后才会出现问题。那就要看一下==底层是如何进行实现的。Java是跨平台语言,java代码在任意系统执行流程是先编译成class文件,然后class文件编译成汇编代码,各操作系统底层都是执行的都是汇编指令。那现在使用javap -c命令将class文件反编译成汇编代码。执行之后截图如下:

    对于integer类型使用==比较大小实际调用了Integer valueOf方法,源码如下:

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

    就是说如果参数大于等于-128并且小于等于Integer.IntegerCache.high就会从IntegerCache中获取,否则重新创建一个Integer对象。好继续看IntegerCache是什么。

  
 private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];

        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);

            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }

通过源码可知:
     IntegerCache的最小值low为-128,IntegerCache的最大值high默认为127;通过注释可知high可以通过启动应用程序时加上 -XX:AutoBoxCacheMax= 选项来指定high的值.所以这就说明了对于integer类型的会员卡id使用==进行比较时项目上线没有出现问题,运行一段时间之后才出现问题是因为新增的会员卡id还没超过127.
     总结:关于整数类型比较大小,如果数据类型为int,可以使用==进行比较;如果是integer类型,最好还是使用equals进行比较。
     有些编码规范平常书写要注意,当然遇到问题处理一次加深一下印象也是好事,不过线上问题犯错的代价不要太大就好。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/871261.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号