找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

6264

积分

1

好友

784

主题
发表于 前天 20:11 | 查看: 0| 回复: 0
Integer a = 1000;
Integer b = 1000;

Integer c = 100;
Integer d = 100;

System.out.println(a == b); // false
System.out.println(c == d); // true

这段代码第一次看到,确实有点膈应。

同样是 Integer,同样是两个一模一样的数字:

1000 == 1000  -> false
100  == 100   -> true

难不成 Java 觉得 100 比 1000 更相等?

当然不是。

这种问题我一般不在 == 上绕,先盯住一个地方:

Integer a = 100;

右边明明是个 int,左边却是 Integer。

中间肯定有人动了手脚。

这个动作就是自动装箱。

编译器看到:

Integer count = 100;

实际走的效果相当于:

Integer count = Integer.valueOf(100);

注意,不是:

new Integer(100);

问题基本就藏在 Integer.valueOf() 这里。

把它的逻辑缩一下,大概可以理解成这样:

static Integer box(int value){
    if (value >= -128 && value <= 127) {
        return SMALL_NUMBERS[value + 128];
    }

    return new Integer(value);
}

这不是让你自己实现一个 Integer,只是把关键逻辑拎出来看。

Java 对一小段常用整数做了缓存。

默认至少包括:

-128 ~ 127

所以执行:

Integer c = 100;
Integer d = 100;

背后相当于两次去缓存里拿 100 对应的那个 Integer 对象。

可以把现场想成这样:

c ─────┐
       ├──> Integer(100)
d ─────┘

两个引用指向同一个对象。

这时候:

c == d

当然就是:

true

再看 1000。

Integer a = 1000;
Integer b = 1000;

1000 默认已经跑出这段缓存范围了。

两次装箱通常会各自得到一个 Integer 对象:

a ─────> Integer(1000)

b ─────> Integer(1000)

里面的数字一样。

对象不是同一个。

于是:

a == b

结果就是:

false

到这里还得补一刀,因为真正容易把人坑进去的是 ==。

== 到底比较了什么?

如果两边都是基本类型:

int x = 1000;
int y = 1000;

System.out.println(x == y);

结果毫无悬念:

true

因为 int 比的是数值。

但换成:

Integer x = 1000;
Integer y = 1000;

Integer 是对象。

两个引用之间使用:

x == y

比较的是它们是不是指向同一个对象。

不是比较对象里面那个数字是不是相等。

这也是为什么下面这段代码完全不需要考虑什么 127:

Integer x = new Integer(100);
Integer y = new Integer(100);

System.out.println(x == y);

结果还是:

false

因为你已经明确 new 了两个对象。

一个 new 一块对象,另一个 new 又一块对象。

缓存根本没机会插手。

反过来:

System.out.println(x.equals(y));

才是:

true

Integer.equals() 比较的是它保存的整数值。

所以业务代码里看到这种东西,我一般会多看一眼:

Integer statusA = getStatusA();
Integer statusB = getStatusB();

if (statusA == statusB) {
    // ...
}

这种写法有个很讨厌的地方。

测试数据如果刚好是:

1
2
10
100

它可能一直跑得好好的。

哪天业务值变成:

200
1000
10000

逻辑突然不进去了。

代码一行没改。

数据一变,Bug 出来了。

这种问题排查起来很容易往业务条件上跑,实际上就是拿对象引用做了比较。

对于 Integer 这种包装类型,我更愿意直接写:

if (Objects.equals(statusA, statusB)) {
    // ...
}

而不是:

if (statusA == statusB) {
    // 别这么比 Integer
}

Objects.equals() 还有个实际好处,能顺手兜住 null。

比如:

Integer expected = null;
Integer actual = 100;

System.out.println(Objects.equals(expected, actual));

不会因为你直接调:

expected.equals(actual)

再额外送一个 NullPointerException。

还有一种写法也经常让人判断错:

Integer x = 1000;

System.out.println(x == 1000);

这个结果是:

true

看到这里别又怀疑缓存失效了。

这里两边类型不一样:

Integer
int

比较时 x 会被自动拆箱,大致变成:

x.intValue() == 1000

最后比的是两个 int。

自然是 true。

所以这几组代码最好放一起看:

Integer a = 100;
Integer b = 100;
System.out.println(a == b);          // true

Integer c = 1000;
Integer d = 1000;
System.out.println(c == d);          // false

System.out.println(c.equals(d));     // true

System.out.println(c == 1000);       // true

看起来四行结果乱七八糟,其实背后就两件事:

Integer 装箱时会对一部分小整数复用对象;
== 碰到两个对象引用时,比较的是对象身份,不是里面保存的整数值。

我平时不会去背“100 为什么行,1000 为什么不行”这种题。

看到:

Integer
Long
Short
Character
Boolean

再看到:

==

第一反应就该是先把自动装箱、拆箱和对象比较捋清楚。

至于 Integer 的缓存范围,记住默认至少有:

-128 ~ 127

就够用了。

业务代码更重要的一条是:

Integer a = ...;
Integer b = ...;

Objects.equals(a, b);

别拿 == 赌缓存。

这种代码现在没出问题,很多时候只是因为你的数据还比较小。




上一篇:Jev 决策AI深度拆解:不聊天的AI,凭什么比通用大模型快200倍
下一篇:AI 生成可编辑幻灯片,开源工具 Oh My PPT 也能导出 PPTX 二次修改
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-10-3 00:15 , Processed in 1.730166 second(s), 46 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表