专栏首页王磊的博客漫画:Integer 竟然有 6 种比较方式?

漫画:Integer 竟然有 6 种比较方式?

代码测试

public class IntegerTest {
    public static void main(String[] args) {
        Integer i1 = 127;
        Integer i2 = 127;
        System.out.println(i1 == i2);
        Integer i3 = 128;
        Integer i4 = 128;
        System.out.println(i3 == i4);
    }
}

以上代码的执行结果为:

true false

首先,当我们将以上的测试代码编译为字节码(.class)之后,编码的代码如下:

public class IntegerTest {
  public static void main(String[] paramArrayOfString) {
    Integer integer1 = Integer.valueOf(127);
    Integer integer2 = Integer.valueOf(127);
    System.out.println((integer1 == integer2));
    Integer integer3 = Integer.valueOf(128);
    Integer integer4 = Integer.valueOf(128);
    System.out.println((integer3 == integer4));
  }
}

可以看出在创建 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,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;
    }

    private IntegerCache() {}
}

从上述源码可以看出,在 Integer 的取值在 -128 到 127 之间时,它会复用已有的对象,因此在 i1(127)和 i2 使用 == 对比时值才会为 true,而当取值变为 128 时,则执行的结果为 false。

这一点其实在阿里巴巴的《Java开发手册》中也有相应的规定,规定的内容如下:

【强制】所有整型包装类对象之间值的比较,全部使用 equals 方法比较。

说明:对于 Integer var = ? 在 -128 至 127 之间的赋值,Integer 对象是在 IntegerCache.cache 产生, 会复用已有对象,这个区间内的 Integer 值可以直接使用 == 进行判断,但是这个区间之外的所有数据,都 会在堆上产生,并不会复用已有对象,这是一个大坑,推荐使用 equals 方法进行判断。

注意事项

不仅如此,当我们使用 new Integer 时,无论值为多少都不能使用 == 比较,示例代码如下:

public class IntegerTest {
    public static void main(String[] args) {
        Integer i1 = new Integer(127);
        Integer i2 = new Integer(127);
        System.out.println(i1 == i2);
    }
}

以上代码的执行结果为:

false

这是因为 new Integer 方法并没有使用到 IntegerCache,而是直接创建了新对象,因此就不能用 == 比较了。

小贴士:== 是用来直接比对两个对象的引用是否相同的,而 equals 则是用来对比两个对象的值是否相同的。

其他比较方式

compareTo

因为 Integer 类实现了 Comparable 接口,因此我们可以使用 compareTo 来对比两个值的大小,实现源码如下:

public final class Integer extends Number implements Comparable<Integer> {
 // 忽略其他内容
}

compareTo 的使用如下:

public class IntegerTest {
    public static void main(String[] args) {
        Integer i1 = new Integer(128);
        Integer i2 = new Integer(128);
        System.out.println(i1.compareTo(i2));
    }
}

以上代码的执行结果为:

0

compareTo 的源码如下:

public int compareTo(Integer anotherInteger) {
    return compare(this.value, anotherInteger.value);
}
public static int compare(int x, int y) {
    return (x < y) ? -1 : ((x == y) ? 0 : 1);
}

由此可以看出 compareTo 的返回值总共有三个:-1、0、1,其中 -1 表示前一值小于后一个值;0 表示两个值相等;1 表示前一个值大于后一个值,因此我们用它来比较两个 Integer 的值是否相等。

直接运算

compareTo 方法给我们了一个启发,我们可以直接将两个值进行相减,如果相减的值等于 0,则说明对比的两个值是相同的,示例代码如下:

public class IntegerTest {
    public static void main(String[] args) {
        Integer i1 = new Integer(128);
        Integer i2 = new Integer(128);
        System.out.println((i1 - i2) == 0);
    }
}

以上代码的执行结果为:

true

intValue

我们可以使用 intValue 得到 Integer 的 int 值,然后再使用 == 进行比较,示例代码如下:

public class IntegerTest {
    public static void main(String[] args) {
        Integer i = 558;
        Integer i2 = 558;
        System.out.println(i.intValue() == i2.intValue());
    }
}

以上代码的执行结果为:

true

异或

异或是一个数学运算符,它应用于逻辑运算。在计算机中如果 a、b 两个值不相同,则异或结果为 1;如果 a、b 两个值相同,异或结果为 0。

比如:

  • 1 异或 0=1
  • 0 异或 0=0
  • 1 异或 1=0

异或实现示例如下:

public class IntegerTest {
    public static void main(String[] args) {
        Integer i = 558;
        Integer i2 = 558;
        System.out.println((i ^ i2) == 0);
    }
}

以上代码的执行结果为:

true

扩展知识:IntegerCache 值域修改

IntegerCache 默认的取值范围为 -128 到 127,但我们可以通过设置启动参数来调整 IntegerCache 的最大缓存值,比如我们可以配置虚拟机的启动参数 -XX:AutoBoxCacheMax=1000,此配置表示将缓存的最大值设置为 1000,如果是 Idea 的配置如下:

此时我们编写一个测试代码:

public class IntegerTest {
    public static void main(String[] args) {
        Integer i1 = 999;
        Integer i2 = 999;
        System.out.println(i1 == i2);
    }
}

以上代码的执行结果为:

true

从运行的结果可以看出 IntegerCache 的取值范围被成功的更改了。

总结

本文我们介绍了 Integer 的 6 种比较方式:==、equals、compareTo、直接运算,而 == 方式并不能用于 Integer 的比较,它只适用于非 new Integer 的一定范围内(-128~127),而后 5 种方式都可以正常用于 Integer 的比较,其中 equals 的比较方式是最为常用的。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • c#生成一组不同的随机数的方法

    #region 生成不同随机数的方法 /// <summary> /// 生成不同随机数的方法 /// </summary> /// <param name="...

    Java中文社群_老王
  • Spring Boot 最佳实践(五)Spring Data JPA 操作 MySQL 8

    JPA(Java Persistence API)Java持久化API,是 Java 持久化的标准规范,Hibernate是持久化规范的技术实现,而Spring...

    Java中文社群_老王
  • NVelocity标签设置缓存的解决方案

      意外的问题总会让人措手不及,今天与大家分享的就是NVelocity设置缓存的问题,之前刚google了一下发现没什么太好的解决方案,希望在这能为需要的朋友找...

    Java中文社群_老王
  • Java Integer(-128~127)值的==和equals比较产生的思考

    最近在项目中遇到一个问题,两个值相同的Integer型值进行==比较时,发现Integer其中的一些奥秘,顺便也复习一下==和equals的区别,先通过Damo...

    用户1205080
  • Java开发知识之Java的包装类

        包装类的意思就是对基本数据类型封装成一个类.这些类都是Number的子类.区别就是封装数据类型不同.包含的方法基本相同.

    IBinary
  • Flink SQL vs Spark SQL

    Spark已经在大数据分析领域确立了事实得霸主地位,而Flink则得到了阿里系的亲赖前途一片光明。我们今天会SparkSQL和FlinkSQL的执行流程进行一个...

    麒思妙想
  • JavaSE的自动装箱和自动拆箱

    内心怀揣自己的真是答案,我们看看下边的源代码: 先看看Integer装箱和拆箱的函数源码:

    静默加载
  • 再谈Integer对象比较

    在上一篇文章中介绍了Integer的特性及面试中常考的几个知识点,本篇文章再做些扩充。

    小诸葛
  • 基本数据类型的包装类

    JAVA 并不是纯面向对象的语言。Java 语言是一个面向对象的语言,但是 Java 中的基本数据类型却是不面向对象的。但是我们在实际使用中经常需要将基本数据转...

    帅飞
  • 面试官六连问拆箱装箱Integer那些事,给我整懵圈了!

    小萌:由于基本数据类型不是对象,所以java并不是纯面向对象的语言,好处是效率较高(全部包装为对象效率较低)。Java是一个面向对象的编程语言,基本类型并不具有...

    乔戈里

扫码关注云+社区

领取腾讯云代金券