杰瑞科技汇

Java int与Integer有何本质区别?

核心区别:基本类型 vs. 包装类

这是最根本的区别。

Java int与Integer有何本质区别?-图1
(图片来源网络,侵删)
特性 int Integer
类型 基本数据类型 包装类
本质 它不是一个对象,是 Java 语言内置的一种数据类型,用于表示整数。 它是一个对象,是 int 基本类型的“包装器”。Integer 类是 java.lang 包中的一个 final 类。
存储位置 值直接存储在栈内存中。 对象存储在堆内存中,变量(引用)存储在栈内存中,指向堆中的对象。
默认值 0 null (非常重要!)
功能 只能表示一个数值,不能调用方法。 拥有很多有用的静态方法和实例方法toString(), parseInt(), compareTo() 等。
性能 占用内存小,计算速度快,直接在栈上操作。 作为对象,创建和销毁有额外的开销,内存占用较大。

Integer 的存在意义

既然已经有了 int,为什么还需要 Integer 呢?主要有以下几个原因:

a. 泛型支持

Java 的泛型(Generics)无法使用基本类型,你不能创建一个 List<int>,但可以创建一个 List<Integer>

// 错误的用法
// List<int> numberList = new ArrayList<>();
// 正确的用法
List<Integer> numberList = new ArrayList<>();
numberList.add(10); // 自动装箱

b. 可以是 null

int 的默认值是 0,但 0 本身是一个有效的数值,在某些场景下,我们需要一个值来表示“不存在”或“未知”,这时,Integernull 值就非常有用。

// 一个用户可能没有填写年龄
Integer userAge = null; // 表示年龄未知
// 而 int 无法表示这种“未知”状态
// int userAge = 0; // 0岁也是一个有效的年龄,无法区分“未知”和“0岁”

c. 提供丰富的工具方法

Integer 类封装了大量与整数操作相关的静态方法,非常方便。

Java int与Integer有何本质区别?-图2
(图片来源网络,侵删)
// 字符串转整数
String str = "123";
int num = Integer.parseInt(str);
// 获取整数的最大/最小值
int max = Integer.MAX_VALUE; // 2147483647
int min = Integer.MIN_VALUE; // -2147483648
// 转换为字符串
Integer myInt = 100;
String strFromInt = myInt.toString();

自动装箱与拆箱

为了在 intInteger 之间方便地转换,Java 5 引入了自动装箱自动拆箱机制。

a. 自动装箱

int 类型的值需要被赋给一个 Integer 类型的变量时,JVM 会自动调用 Integer.valueOf(int) 方法,将其转换为 Integer 对象。

// 在 Java 5 之前,需要手动装箱
// Integer i = new Integer(10);
// Java 5 之后,自动装箱
Integer i = 10; // JVM 内部执行了 Integer i = Integer.valueOf(10);

b. 自动拆箱

Integer 类型的值需要被赋给一个 int 类型的变量,或者参与算术运算时,JVM 会自动调用 Integer.intValue() 方法,将其拆箱为 int 值。

// 在 Java 5 之前,需要手动拆箱
// int primitive = i.intValue();
// Java 5 之后,自动拆箱
int primitive = i; // JVM 内部执行了 int primitive = i.intValue();
int sum = i + 5;   // i 先被拆箱为 10,10 + 5 = 15

⚠️ 自动装箱/拆箱的陷阱

这个机制虽然方便,但也带来了一些需要特别注意的问题。

Java int与Integer有何本质区别?-图3
(图片来源网络,侵删)

陷阱 1:NullPointerException 由于 Integer 对象可以是 null,如果尝试对一个 nullInteger 变量进行拆箱,就会抛出 NullPointerException

Integer count = null;
// 下面的代码会抛出 NullPointerException
int intCount = count; // 尝试拆箱,但 count 是 null

陷阱 2:性能问题与对象开销 在一个循环中频繁地创建和销毁 Integer 对象会影响性能。

// 性能较差的写法
Long sum = 0L;
for (long i = 0; i < Integer.MAX_VALUE; i++) {
    sum += i; // 每次循环都会创建一个新的 Long 对象
}

陷阱 3: 比较的陷阱 这是面试中非常经典的问题。 比较的是两个变量的内存地址(引用)。

  • 对于 int: 比较的是值。
  • 对于 Integer: 比较的是两个对象的地址是否相同。

Integer 的缓存机制(重点) 为了提高性能和减少内存占用,Integer 类在内部实现了一个 IntegerCache(缓存池),默认情况下,这个池缓存了 -128127 之间的所有 Integer 对象。

Integer a = 127;
Integer b = 127;
System.out.println(a == b); // 输出 true,因为 a 和 b 指向缓存池中同一个对象
Integer c = 128;
Integer d = 128;
System.out.println(c == d); // 输出 false,因为 128 超出缓存范围,c 和 d 是两个不同的新对象
// 手动创建的 Integer 对象不会进入缓存池
Integer e = new Integer(127);
Integer f = new Integer(127);
System.out.println(e == f); // 输出 false,e 和 f 是两个通过 new 关键字创建的不同对象

比较 IntegerintIntegerint 进行 比较时,Integer 会被自动拆箱为 int,然后比较两个 int 的值。

Integer g = 100;
int h = 100;
System.out.println(g == h); // 输出 true,g 被拆箱为 100,100 == 100
Integer i = new Integer(100);
int j = 100;
System.out.println(i == j); // 输出 true,i 被拆箱为 100,100 == 100

何时使用 int,何时使用 Integer

场景 推荐类型 原因
方法参数/返回值 优先使用 int 除非你需要用 null 表示特殊含义(如“未找到”、“未知”)。int 更高效,避免了 NullPointerException 的风险。
集合类(List, Set, Map)的键或值 必须使用 Integer 集合只能存储对象,不能存储基本类型。
数据库字段映射 通常使用 Integer 数据库的 NULL 值可以完美映射到 Java 的 Integer,而 int 无法处理 NULL,ORM 框架(如 MyBatis, JPA)通常会使用包装类。
JSON/XML 序列化/反序列化 通常使用 Integer JSON/XML 中的 null 值可以映射到 Integer,而 int 会被强制赋值为 0,可能导致数据丢失。

int Integer
一句话总结 原始的、快速的、不能为空的整数。 对象的、功能丰富的、可以为空的整数。
核心 基本类型,栈内存,值是 0 引用类型,堆内存,值可以是 null
转换 无需转换,直接使用。 通过自动装箱/拆箱与 int 交互。
选择 默认选择,当你只需要一个整数,且不需要 null 语义时。 特殊需求,当你需要 null 语义、使用泛型、或利用其工具方法时。

理解 intInteger 的区别,是迈向 Java 中高级开发的关键一步,能帮助你写出更健壮、更符合 Java 语言习惯的代码。

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