int 是基本数据类型,而 Integer 是 int 的包装类。

下面我们从多个维度进行详细对比。
核心区别一览表
| 特性 | int |
Integer |
|---|---|---|
| 类型 | 基本数据类型 | 引用数据类型 (包装类) |
| 默认值 | 0 |
null |
| 存储位置 | 栈内存 | 堆内存 |
| 用途 | 用于数值计算,高效、直接 | 用于面向对象场景,如泛型、集合、可以为null |
| 示例 | int age = 30; |
Integer age = Integer.valueOf(30); |
| 方法 | 无方法 | 有很多方法,如 parseInt(), toString(), compareTo() 等 |
| 自动装箱/拆箱 | 不参与 | 参与 (Java 1.5+ 特性) |
详细解释
基本数据类型 vs. 引用数据类型
这是最根本的区别。
-
int(基本数据类型)- Java 语言内置的、最简单的数据类型。
- 它本身不包含任何复杂的行为或方法,只是一个纯粹的值。
- 它直接存储在栈内存中,访问速度非常快。
-
Integer(引用数据类型)
(图片来源网络,侵删)- 它是一个类,位于
java.lang包下。 - 它是
int的“包装器”,将一个int值包装在一个对象中。 - 作为对象,它存储在堆内存中,栈中只保存指向这个对象的引用。
- 它是一个类,位于
默认值
这个区别在处理类或数组的成员变量时至关重要。
int: 当一个int类型的成员变量被声明但没有初始化时,它的默认值是0。Integer: 当一个Integer类型的成员变量被声明但没有初始化时,它的默认值是null。
示例代码:
public class DefaultValueExample {
// int 类型的成员变量,默认值为 0
private int primitiveInt;
// Integer 类型的成员变量,默认值为 null
private Integer wrapperInteger;
public static void main(String[] args) {
DefaultValueExample example = new DefaultValueExample();
System.out.println("primitiveInt 的默认值: " + example.primitiveInt); // 输出 0
System.out.println("wrapperInteger 的默认值: " + example.wrapperInteger); // 输出 null
// 尝试对 wrapperInteger 进行算术运算,会抛出 NullPointerException
// example.wrapperInteger = example.wrapperInteger + 1; // 这行代码会崩溃!
}
}
最佳实践:当你需要一个变量可以表示“无数字”或“未知”状态时(数据库中的字段可能为空),必须使用
Integer,因为null可以明确地表示这种状态。
与集合和泛型的关系
这是 Integer 不可替代的另一个重要场景。
- Java 的集合框架(如
ArrayList,HashMap)只能存储对象,不能存储基本数据类型。 - 泛型(Generics)也不支持基本数据类型。
如果你想把一个 int 类型的数字放进 List 或 Map 的键/值中,你必须使用 Integer。
示例代码:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class CollectionExample {
public static void main(String[] args) {
// List<int> list = new ArrayList<>(); // 编译错误!泛型不支持基本类型
// 正确用法:使用包装类
List<Integer> list = new ArrayList<>();
list.add(10); // 自动装箱:10 -> Integer(10)
list.add(20);
System.out.println("List 中的元素: " + list); // 输出 [10, 20]
Map<String, Integer> map = new HashMap<>();
map.put("age", 25); // 自动装箱
map.put("score", 98);
System.out.println("Map 中的值: " + map); // 输出 {score=98, age=25}
}
}
自动装箱与自动拆箱
为了简化 int 和 Integer 之间的转换,Java 1.5 引入了自动装箱和自动拆箱机制。
-
自动装箱: 将
int类型自动转换为Integer对象。Integer i = 10;等同于Integer i = Integer.valueOf(10);
-
自动拆箱: 将
Integer对象自动转换为int类型。int j = i;等同于int j = i.intValue();
这个特性让开发者可以像使用基本类型一样方便地使用包装类,但背后 JVM 仍然在执行转换操作。
示例代码:
public class AutoBoxingUnboxingExample {
public static void main(String[] args) {
// 自动装箱
Integer integerObj = 100;
// 自动拆箱
int primitiveInt = integerObj;
System.out.println("integerObj: " + integerObj);
System.out.println("primitiveInt: " + primitiveInt);
// 在表达式中混合使用
Integer a = 10;
Integer b = 20;
int sum = a + b; // a 和 b 都会自动拆箱为 int,然后相加
System.out.println("sum: " + sum); // 输出 30
}
}
注意: 自动拆箱有一个潜在的风险。
Integer对象的值为null,尝试进行自动拆箱会抛出NullPointerException,这就是为什么理解默认值的区别非常重要。
缓存机制
Integer 类有一个非常重要的特性:缓存。
为了提高性能和节省内存,Integer 类在内部维护了一个 Integer 对象池,范围是 -128 到 127。
当你使用 Integer.valueOf(int i) 方法(或者直接使用 Integer i = 10; 这种字面量赋值,JVM 会调用 valueOf)创建一个 Integer 对象时:
i的值在-128到127之间,valueOf方法会直接从缓存池中返回一个已经存在的对象,而不是创建新的。i的值不在这个范围内,则会创建一个新的Integer对象。
示例代码:
public class IntegerCacheExample {
public static void main(String[] args) {
Integer a = 127;
Integer b = 127;
System.out.println(a == b); // true,指向缓存池中的同一个对象
Integer c = 128;
Integer d = 128;
System.out.println(c == d); // false,指向堆中两个不同的新对象
// 使用 new 关键字创建,永远都是新对象
Integer e = new Integer(127);
Integer f = new Integer(127);
System.out.println(e == f); // false
}
}
注意: 比较的是两个引用是否指向同一个对象,对于基本类型
int, 比较的是值是否相等。
总结与选择
| 场景 | 推荐使用 | 原因 |
|---|---|---|
| 简单的数学计算 | int |
速度更快,内存占用更小,没有对象开销。 |
| 需要为 null | Integer |
null 可以明确表示“无值”或“未知”状态。 |
| 作为集合或泛型的元素 | Integer |
集合框架只能存储对象。 |
调用 Integer 类的静态方法 |
Integer |
Integer.parseInt("123")。 |
| 作为方法参数,需要传递 null | Integer |
方法无法区分 int 的 0 和未传入的情况。 |
核心思想:
- 追求性能和内存效率,使用
int。 - 需要面向对象的特性、
null值支持或与集合框架集成,使用Integer。
在 Java 1.5 之后,自动装箱/拆箱机制让两者之间的切换变得非常平滑,但开发者仍然需要理解它们背后的区别,以避免 NullPointerException 等潜在问题,并写出更符合 Java 设计思想的代码。
