杰瑞科技汇

Java Integer比较大小,用==还是equals?

(主标题+副标题):

Java Integer 比较大小,别再踩坑了!从“==”到equals(),一篇讲透 用于SEO长尾关键词): Integer 比较大小、Integer 等于、 和 equals() 区别、Java 自动装箱、Java 面试题

Java Integer比较大小,用==还是equals?-图1
(图片来源网络,侵删)

文章正文:

引言:一个看似简单,却让无数开发者“翻车”的问题

“Hello, World!” 是每个程序员的起点,而 Integer 的比较大小,几乎是每个 Java 开发者在成长道路上遇到的第一个“甜蜜的陷阱”,你可能会自信满满地写下:

Integer a = 100;
Integer b = 100;
System.out.println(a == b); // 输出什么?

当你满怀期待地按下运行键,屏幕上可能显示 true,但当你把数字换成 200 时:

Integer c = 200;
Integer d = 200;
System.out.println(c == d); // 输出什么?

结果却变成了 false

是不是瞬间感觉自己的 Java 世界观受到了冲击?别担心,你不是一个人,我们就来彻底、清晰地剖析 Integer 比较大小的所有细节,让你不仅知其然,更知其所以然,轻松应对任何相关面试和开发场景。

Java Integer比较大小,用==还是equals?-图2
(图片来源网络,侵删)

第一部分:为什么会出问题?—— 罪魁祸首:自动装箱与

要理解这个问题,我们必须先搞清楚两个核心概念:自动装箱 和 运算符。

1 什么是自动装箱?

在 Java 5 之前,我们创建 Integer 对象必须这样写:

Integer num = new Integer(10); // 手动装箱

这种方式很繁琐,为了简化代码,Java 5 引入了“自动装箱”特性,这意味着,当你把一个基本数据类型 int 赋值给一个 Integer 对象时,Java 编译器会自动为你完成转换。

下面这两行代码在编译后是等价的:

Java Integer比较大小,用==还是equals?-图3
(图片来源网络,侵删)
// 你写的代码
Integer a = 100;
// 编译器背后帮你做的
Integer a = Integer.valueOf(100);

关键点就在这里:Integer.valueOf() 方法

2 Integer.valueOf() 的“缓存”机制

为了提高性能和节省内存,java.lang.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 是什么呢?它是一个静态的 Integer 数组,在类加载时就会初始化。

// IntegerCache 类的简化逻辑
private static class IntegerCache {
    static final int low = -128;
    static final int high = 127; // 关键!
    static final Integer cache[];
    static {
        // ... 初始化一个从 -128 到 127 的 Integer 对象数组
        cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);
    }
}

结论来了:

当你通过自动装箱(Integer a = 100;)创建一个 Integer 对象时,Integer.valueOf(100) 会被调用,如果传入的值在 -128 到 127 这个范围内,它会直接从 IntegerCache 缓存中返回一个已经创建好的对象实例。

  • Integer a = 100; -> Integer.valueOf(100) -> 从缓存返回一个 Integer 对象。
  • Integer b = 100; -> Integer.valueOf(100) -> 再次从缓存返回同一个 Integer 对象

ab 实际上指向的是内存中的同一个对象,而 在比较两个对象引用时,比较的就是它们是否指向同一个内存地址。a == b 的结果是 true

但当值超过 127 时,200:

  • Integer c = 200; -> Integer.valueOf(200) -> 不在缓存范围内,new Integer(200) 创建了一个全新的对象
  • Integer d = 200; -> Integer.valueOf(200) -> 同样不在缓存范围内,new Integer(200) 创建了另一个全新的对象

cd 指向的是内存中两个不同的对象,c == d 的结果是 false


第二部分:正确的比较姿势 —— equals()compareTo()

知道了 为什么会“失灵”,那么我们该如何正确地比较 Integer 的大小呢?

1 使用 equals() 方法进行“值”比较

Object 类提供了 equals() 方法,其设计初衷是比较两个对象的“内容”是否相等。Integer 类重写了这个方法,使其专门比较 int 的值。

Integer a = 100;
Integer b = 100;
Integer c = 200;
Integer d = 200;
// 比较的是 Integer 对象中存储的 int 值
System.out.println(a.equals(b)); // true, 值相等
System.out.println(c.equals(d)); // true, 值相等
System.out.println(a.equals(c)); // false, 值不等

equals() 是比较 Integer 对象值的标准方式。 但要注意,它不能直接和 int 基本类型一起使用,会编译报错,除非先把 int 转为 Integer

int num = 100;
Integer obj = 100;
// 正确
System.out.println(obj.equals(num)); // Java 会自动将 num 装箱,比较 100 == 100
// 错误!
// System.out.println(num.equals(obj)); // int 类型没有 equals 方法

2 使用 compareTo() 方法进行“大小”比较

如果你不仅想知道是否相等,还想知道谁大谁小,Integer 实现了 Comparable 接口,提供了 compareTo() 方法。

它的返回值规则非常清晰:

  • 返回 0:表示两个值相等。
  • 返回负整数:表示调用此方法的值小于参数值。
  • 返回正整数:表示调用此方法的值大于参数值。
Integer x = 500;
Integer y = 300;
System.out.println(x.compareTo(y)); // 输出 200 (正数), 表示 x > y
System.out.println(y.compareTo(x)); // 输出 -200 (负数), 表示 y < x
System.out.println(x.compareTo(x)); // 输出 0, 表示 x == x

在需要排序或比较大小关系的场景下(TreeSetCollections.sort()),compareTo() 是不二之选。


第三部分:终极实践指南与代码示例

理论讲完了,我们来看一个综合性的例子,巩固所有知识点。

public class IntegerComparisonGuide {
    public static void main(String[] args) {
        // 场景1:值在缓存范围内 [-128, 127]
        Integer a1 = 127;
        Integer a2 = 127;
        System.out.println("--- 场景1:值在缓存范围内 ---");
        System.out.println("a1 == a2 (引用比较): " + (a1 == a2)); // true
        System.out.println("a1.equals(a2) (值比较): " + a1.equals(a2)); // true
        System.out.println("a1.compareTo(a2) (大小比较): " + a1.compareTo(a2)); // 0
        // 场景2:值超出缓存范围
        Integer b1 = 128;
        Integer b2 = 128;
        System.out.println("\n--- 场景2:值超出缓存范围 ---");
        System.out.println("b1 == b2 (引用比较): " + (b1 == b2)); // false
        System.out.println("b1.equals(b2) (值比较): " + b1.equals(b2)); // true
        System.out.println("b1.compareTo(b2) (大小比较): " + b1.compareTo(b2)); // 0
        // 场景3:一个对象,一个基本类型
        int c1 = 100;
        Integer c2 = 100;
        System.out.println("\n--- 场景3:一个对象,一个基本类型 ---");
        // System.out.println("c1 == c2: " + (c1 == c2)); // 编译错误!类型不匹配
        System.out.println("c2 == c1 (自动拆箱后比较): " + (c2 == c1)); // true, c2 被自动拆箱为 int
        System.out.println("c2.equals(c1) (自动装箱后比较): " + c2.equals(c1)); // true
        // 场景4:比较两个不同的值
        Integer d1 = 50;
        Integer d2 = 60;
        System.out.println("\n--- 场景4:比较两个不同的值 ---");
        System.out.println("d1 == d2: " + (d1 == d2)); // false
        System.out.println("d1.equals(d2): " + d1.equals(d2)); // false
        System.out.println("d1.compareTo(d2): " + d1.compareTo(d2)); // -1 (d1 < d2)
        System.out.println("d2.compareTo(d1): " + d2.compareTo(d1)); // 1 (d2 > d1)
    }
}

第四部分:总结与最佳实践

为了避免未来再出现类似的困惑,请牢记以下“黄金法则”:

你的需求 推荐方法 原因
判断两个 Integer 对象的值是否相等 a.equals(b) 严格比较对象内容,不受缓存和 引用比较的影响。
判断 Integer 对象与 int 基本类型的值是否相等 intValue == intValueintegerObj.equals(intValue) 直接比较数值最直观。 会触发自动拆箱,性能略好。
需要比较大小(大于、小于、等于) a.compareTo(b) 语义清晰,专为排序和比较设计,返回值信息丰富。
绝对不要用 来比较两个 Integer 对象的值 (避免) 比较的是引用地址,其行为受 Integer 缓存机制影响,极不可靠,是新手最容易犯的错误。

一句话总结:

想比值,用 equals();想比大小,用 compareTo();想比引用(你知道你在干什么时),才用 。

希望这篇文章能帮你彻底搞懂 Java Integer 比较大小的所有奥秘,如果你觉得有收获,欢迎点赞、收藏并分享给身边的朋友,让更多人避开这个“坑”!

分享:
扫描分享到社交APP
上一篇
下一篇