Integer的比较防坑

java基础 - Integer的比较防坑

我们都知道Integer的存储结构,以及和int的自动拆装箱。所以我一般简单处理直接用equals完事,但是还是会踩坑,菜的没边了,,,做个记录。


目录

java基础 - Integer的比较防坑

一、Integer与int

二、Interger与Integer

三、Integer与String

总结:


一、Integer与int

1、int是java中的8大基本数据类型之一。

2、Ingeter是int的包装类,是对象。

3、int的初值为0,Ingeter的初值为null

4、int是基本数据类型,存在常量池。Ingeter的情况比较多,用new的是在堆,对于-128到127之间的数,会进行缓存,Integer i5 = 127时,会将127进行缓存,超出直接new。

java在编译Integer i2 = 128的时候,被翻译成-> Integer i2 = Integer.valueOf(128);而valueOf()函数会对-128到127之间的数进行缓存。

5、Integer和int会自动拆装箱,所以==直接为值比较,为true

//range [-128, 127]的直接从Integer[] cache缓存中获取
public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }




//这是Interger的区间和缓存,一般为range [-128, 127]
private static class IntegerCache {

        //下区间是-128
        static final int low = -128;
        //这里的high没给定,但是下面静态代码块给了
        static final int high;
        static final Integer cache[];

//静态代码块逻辑:
//1、当high属性为空时 low = -128,high=127,cache[127+128+1]
//2、当high属性不为空时 low = -128,high>=127,cache[high+128+1]
//3、遍历填充了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);

                    //最小127
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    //public static final int   MAX_VALUE = 0x7fffffff;  
                    // 0x7FFFFFFF 的二进制表示就是除了首位是 0,其余都是1就是说,这是最大的整型数 int           //最大不超过int边界
                    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;
        }

        private IntegerCache() {}
    }

 

private final int value;

public Integer(int value) {
        this.value = value;
    }

public Integer(String s) throws NumberFormatException {
        this.value = parseInt(s, 10);
    }

测试代码:

    @Test
    public void intTest() {
        //int与integer
        int a = 128;
        Integer b = 128;
        Integer c = new Integer(128);
        log.info("a==b|结果{}",a==b);//true 会自动拆箱,值比较
        log.info("a==c|结果{}",a==c);//true 会自动拆箱,值比较
        log.info("b==c|结果{}",b==c);//false  两个new的对象,地址指针不一样
    }


二、Interger与Integer

1、还是需要再次注意,java在编译Integer i2 = 128的时候,被翻译成-> Integer i2 = Integer.valueOf(128);而valueOf()函数会对-128到127之间的数进行缓存。源码上面有。所以-128到127之间的地址是相同的,都在同一个缓存数组中,超出时会new一个integer,是一个新的对象了,地址指针不一样,==比较为false。

2、new 关键字直接新建一个对象。

3、实现了Comparable, 有comparaTo()方法。

4、Integer继承了Number,它是一个对象,有equals()方法。

     


private final int value;


    //Integer a=new Integer(1);
    public Integer(int value) {
        this.value = value;
    }

    //Integer a=new Integer("1");
    public Integer(String s) throws NumberFormatException {
        this.value = parseInt(s, 10);
    }
private final int value;

//Integer的compareTo比较最终为int值比较
public int compareTo(Integer anotherInteger) {
        return compare(this.value, anotherInteger.value);
    }

//x与y比较,相等返回0,小于返回-1,大于返回1
public static int compare(int x, int y) {
        return (x < y) ? -1 : ((x == y) ? 0 : 1);
    }

 

 

 

public boolean equals(Object obj) {

        //一定要注意这里,不为Integer类型时,返回false
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }


  public int intValue() {
        return value;
    }

测试代码:

 @Test
    public void integerTest() {
        //integer与integer

        //range[-128,127]之间比较
        Integer a = 127;
        Integer b = 127;
        Integer c = new Integer(127);
        Integer d = new Integer(127);
        log.info("127|a==b|结果{}",a==b); //true  [-128,127]之间,数组缓存Integer[] cache,地址指针一样
        log.info("127|a==c|结果{}",a==c); //flase  a为数组缓存Integer[] cache, c直接new对象,地址指针不一样
        log.info("127|c==d|结果{}",c==d); //flase  new对象,地址指针不一样
        log.info("127|a.equals(b)|结果{}",a.equals(b)); //true  equals为value值比较
        log.info("127|a.equals(c)|结果{}",a.equals(c)); //true  equals为value值比较
        log.info("127|c.equals(d)|结果{}",c.equals(d)); //true  equals为value值比较
        log.info("127|a.compareTo(b)|结果{}",a.compareTo(b)); // 0 compareTo也是value值比较
        log.info("127|a.compareTo(c)|结果{}",a.compareTo(c)); // 0 compareTo也是value值比较
        log.info("127|c.compareTo(d)|结果{}",c.compareTo(d)); // 0 compareTo也是value值比较


        Integer a1 = 128;
        Integer b1 = 128;
        Integer c1 = new Integer(128);
        Integer d1 = new Integer(128);
        log.info("128|a1==b1|结果{}",a1==b1); //false  128时没有走数组缓存Integer[] cache,直接new Integer(),地址指针不一样
        log.info("128|a1==c1|结果{}",a1==c1); //flase  a1为数组缓存Integer[] cache, c1直接new对象,地址指针不一样
        log.info("128|c1==d1|结果{}",c1==d1); //flase  new对象,地址指针不一样
        log.info("128|a1.equals(b1)|结果{}",a1.equals(b1)); //true  equals为value值比较
        log.info("128|a1.equals(c1)|结果{}",a1.equals(c1)); //true  equals为value值比较
        log.info("128|c1.equals(d1)|结果{}",c1.equals(d1)); //true  equals为value值比较
        log.info("128|a1.compareTo(b1)|结果{}",a1.compareTo(b1)); // 0 compareTo也是value值比较
        log.info("128|a1.compareTo(c1)|结果{}",a1.compareTo(c1)); // 0 compareTo也是value值比较
        log.info("128|c1.compareTo(d1)|结果{}",c1.compareTo(d1)); // 0 compareTo也是value值比较

    }

 

 

1、Integer ==比较时,要注意如果值不能确定在[-128,127]的缓存区间,不要使用==比较。


三、Integer与String

知道了Integer [-128,127]的缓存区间问题,还是经常踩坑,也是,,,,且看下文源码和测试

//Integer equals

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


//String equals
public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

测试代码

 @Test
    public void stringTest() {
        //integer与String
        Integer b = 1;  //编译时为Integer.valueOf(1);
        Integer c = new Integer(1);
        //value = parseInt(s, 10);
        Integer d = new Integer("1");
        String e = "1";

        log.info("b.equals(c)|结果{}", b.equals(c)); //true  equals为value值比较
        log.info("b.equals(d)|结果{}", b.equals(d)); //true  equals为value值比较
        log.info("c.equals(d)|结果{}", c.equals(d)); //true  equals为value值比较
        log.info("b.equals(e)|结果{}", b.equals(e)); //false 我常在这踩坑,虽然编译不报错,但 !(obj instanceof Integer) return  flase
        log.info("c.equals(e)|结果{}", c.equals(e)); //false 我常在这踩坑,虽然编译不报错,但 !(obj instanceof Integer) return  flase
        log.info("d.equals(e)|结果{}", d.equals(e)); //false 我常在这踩坑,虽然编译不报错,但 !(obj instanceof Integer) return  flase
        log.info("b.equals(Integer.valueOf(e))|结果{}", b.equals(Integer.valueOf(e))); //true 如果遇到Integer 与String的比较,一定转成相同类型再equals
        log.info("e.equals(b)|结果{}", e.equals(b)); //flase !(anObject instanceof String) return  flase
        log.info("e.equals(String.valueOf(b))|结果{}", e.equals(String.valueOf(b))); //true 如果遇到Integer 与String的比较,一定转成相同类型再equals

    }

 

测试结果

总结:

防了Integer [-128,127]的缓存区间 == 的问题 ,也要防equals类型不一致的问题,反正我常在这踩坑。


总结:

1、如果是int和Integer,目前高版本会自动拆箱,直接可以==值比较

2、要理解 Integer [-128,127]的缓存区间原理,因为常用Integer的字典,能确定在缓存区间内,就可以用 ==,地址指针一样,都是Integer[] cache 中的

3、由于入参问题,常常会以String接收的参数与字典Integer比较,这时一定要注意保持类型一致后再equals

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值