Java面试高频题:Integer缓存机制与 equals、== 区别

Java面试高频题:Integer缓存机制与 equals、== 区别

在 Java 面试中,包装类是必考知识点,而 Integer 缓存机制更是高频中的高频。

例如下面这段代码:

java 复制代码
Integer a = 127;
Integer b = 127;

System.out.println(a == b);

输出:

text 复制代码
true

但是:

java 复制代码
Integer a = 128;
Integer b = 128;

System.out.println(a == b);

输出:

text 复制代码
false

为什么会出现这种现象?

本文将从包装类、自动装箱、Integer缓存池以及 equals 和 == 的区别几个方面深入分析。


目录

  • 为什么需要包装类
  • 八大包装类
  • 自动装箱与自动拆箱
  • == 与 equals 的区别
  • Integer缓存机制
  • 为什么127返回true
  • 为什么128返回false
  • Integer源码分析
  • 常见面试题
  • 开发最佳实践
  • 总结

一、为什么需要包装类

Java中的基本数据类型:

java 复制代码
byte
short
int
long

float
double

char

boolean

这些类型虽然效率高,但存在局限性。

例如:

java 复制代码
List<int> list = new ArrayList<>();

编译直接报错。

因为泛型只能使用对象。

因此Java为每种基本类型提供了对应的包装类。


二、八大包装类

基本类型 包装类
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean

示例:

java 复制代码
Integer age = 18;

Double salary = 10000.5;

三、自动装箱与自动拆箱

JDK5之后引入了自动装箱机制。


自动装箱

代码:

java 复制代码
Integer num = 100;

实际上:

java 复制代码
Integer num = Integer.valueOf(100);

编译器自动完成转换。


自动拆箱

代码:

java 复制代码
Integer num = 100;

int value = num;

实际上:

java 复制代码
int value = num.intValue();

示例

java 复制代码
Integer a = 10;

Integer b = 20;

System.out.println(a + b);

执行过程:

text 复制代码
自动拆箱

↓

int运算

↓

自动装箱(如果需要)

四、== 与 equals 的区别

这是面试中的经典问题。


== 比较什么?

对于基本类型:

java 复制代码
int a = 10;
int b = 10;
java 复制代码
a == b

比较的是:

text 复制代码

结果:

text 复制代码
true

对于引用类型:

java 复制代码
String s1 = new String("abc");
String s2 = new String("abc");
java 复制代码
s1 == s2

比较的是:

text 复制代码
对象地址

结果:

text 复制代码
false

因为是两个不同对象。


equals比较什么?

Object源码:

java 复制代码
public boolean equals(Object obj) {
    return (this == obj);
}

默认也是比较地址。


但是很多类重写了equals。

例如:

java 复制代码
String
Integer
Long
BigDecimal
Date

等。


示例:

java 复制代码
String s1 = new String("abc");
String s2 = new String("abc");
java 复制代码
s1.equals(s2)

结果:

text 复制代码
true

因为String重写了equals。

比较的是内容。


五、Integer缓存机制

Integer为了提高性能,避免频繁创建对象,引入了缓存池。

缓存范围:

text 复制代码
-128 ~ 127

这也是面试最常考的知识点。


例如:

java 复制代码
Integer a = 100;
Integer b = 100;

实际上:

java 复制代码
Integer.valueOf(100)

会从缓存池获取对象。

因此:

java 复制代码
a == b

结果:

text 复制代码
true

六、为什么127返回true

示例:

java 复制代码
Integer a = 127;
Integer b = 127;

比较:

java 复制代码
System.out.println(a == b);

输出:

text 复制代码
true

执行过程:

java 复制代码
Integer.valueOf(127)

发现:

text 复制代码
127

属于缓存范围

直接返回缓存对象。


图示:

text 复制代码
IntegerCache

↓

127对象

↑     ↑

a     b

因此:

text 复制代码
a和b指向同一个对象

结果:

java 复制代码
a == b

为:

text 复制代码
true

七、为什么128返回false

代码:

java 复制代码
Integer a = 128;
Integer b = 128;

比较:

java 复制代码
System.out.println(a == b);

输出:

text 复制代码
false

原因:

text 复制代码
128

超出缓存范围

执行:

java 复制代码
Integer.valueOf(128)

时:

text 复制代码
创建新对象

图示:

text 复制代码
a

↓

Integer(128)

──────────

b

↓

Integer(128)

两个对象地址不同。

因此:

java 复制代码
a == b

结果:

text 复制代码
false

八、源码分析

查看 Integer 源码:

java 复制代码
public static Integer valueOf(int i) {

    if (i >= IntegerCache.low &&
        i <= IntegerCache.high) {

        return IntegerCache.cache[i + (-IntegerCache.low)];
    }

    return new Integer(i);
}

核心逻辑:

java 复制代码
如果在缓存范围

直接返回缓存对象

否则创建新对象

继续查看缓存范围:

java 复制代码
static final int low = -128;
java 复制代码
static final int high = 127;

因此:

text 复制代码
-128 ~ 127

被缓存。


九、new Integer为什么不同

示例:

java 复制代码
Integer a = new Integer(127);
Integer b = new Integer(127);

比较:

java 复制代码
System.out.println(a == b);

结果:

text 复制代码
false

原因:

java 复制代码
new

强制创建新对象。

不会走缓存池。


图示:

text 复制代码
a → 对象A

b → 对象B

地址不同。


十、Integer与int比较

示例:

java 复制代码
Integer a = 128;

int b = 128;

System.out.println(a == b);

结果:

text 复制代码
true

原因:

发生自动拆箱。

实际执行:

java 复制代码
a.intValue() == b

变成:

java 复制代码
128 == 128

比较的是值。

因此:

text 复制代码
true

十一、常见面试陷阱

示例1

java 复制代码
Integer a = 127;
Integer b = 127;

System.out.println(a == b);

结果:

text 复制代码
true

示例2

java 复制代码
Integer a = 128;
Integer b = 128;

System.out.println(a == b);

结果:

text 复制代码
false

示例3

java 复制代码
Integer a = 128;
Integer b = 128;

System.out.println(a.equals(b));

结果:

text 复制代码
true

示例4

java 复制代码
Integer a = new Integer(100);
Integer b = new Integer(100);

System.out.println(a == b);

结果:

text 复制代码
false

示例5

java 复制代码
Integer a = 100;
int b = 100;

System.out.println(a == b);

结果:

text 复制代码
true

十二、常见面试题

面试题1

Integer缓存范围是多少?

答案:

text 复制代码
-128 ~ 127

面试题2

为什么127==127返回true?

答案:

text 复制代码
使用缓存对象

地址相同

面试题3

为什么128==128返回false?

答案:

text 复制代码
超出缓存范围

创建两个新对象

面试题4

equals和==区别?

答案:

text 复制代码
==

基本类型比较值

引用类型比较地址

equals

默认比较地址

很多类重写后比较内容

面试题5

Java存在引用传递吗?

答案:

text 复制代码
没有

Java只有值传递

十三、开发最佳实践

1、对象比较优先使用equals

推荐:

java 复制代码
Integer a = 128;
Integer b = 128;

a.equals(b);

不推荐:

java 复制代码
a == b

因为容易受到缓存机制影响。


2、字符串比较使用equals

推荐:

java 复制代码
str1.equals(str2);

不推荐:

java 复制代码
str1 == str2;

3、注意自动拆箱空指针

例如:

java 复制代码
Integer num = null;

int value = num;

运行:

text 复制代码
NullPointerException

原因:

java 复制代码
num.intValue();

空指针异常。


总结

本文介绍了:

  • 包装类的作用
  • 自动装箱与拆箱
  • == 与 equals 区别
  • Integer缓存机制
  • 为什么127返回true
  • 为什么128返回false
  • Integer源码分析
  • 面试高频陷阱题

需要牢记:

text 复制代码
Integer缓存范围:

-128 ~ 127

以及:

text 复制代码
对象比较优先使用equals

避免因为缓存机制导致逻辑错误。


相关推荐
weixin_394758032 小时前
CRMEB Pro 商品字段二开:为什么加一个字段会牵动 SKU、缓存和前端展示?
前端·缓存
Hui Baby2 小时前
MCP SSE协议发送注意
java
仙俊红2 小时前
SpringBoot启动原理
java·spring boot·后端
星间都市山脉2 小时前
Android STS(Security Test Suite)完整介绍与测试流程
android·java·linux·windows·ubuntu·android studio·androidx
namexingyun2 小时前
拆解Fable 5三重安全护栏:模型路由、蒸馏防护与生物安全分类器的技术原理 - 微元算力(weytoken)
java·人工智能·python·安全·架构·ai编程
地铁潜行者2 小时前
加了幂等表,为什么消息重试反而不执行了?聊聊 MQ 消费幂等的边界
java·后端
摇滚侠3 小时前
SpringMVC 入门到实战 视图解析器 44-48
java·spring·maven·intellij-idea
記億揺晃着的那天3 小时前
告别误操作!Spring Boot 多环境配置隔离与启动守卫实战
java·spring boot·后端·环境隔离
我是唐青枫3 小时前
Java Spring Data JPA 实战指南:Repository 查询、分页与实体映射
java·开发语言