一句话概括
int: 是 Java 的一种基本数据类型,它不是对象,只是一个用来存储整数值的容器,直接存储数值本身。Integer: 是int对应的包装类,它是一个对象,内部封装了一个int类型的值,并提供了一系列有用的方法(如parseInt(),toString()等)。
详细对比表格
| 特性 | int (基本数据类型) |
Integer (包装类) |
|---|---|---|
| 本质 | 不是对象,是语言内置的原始类型。 | 是对象,是 java.lang 包中的一个类。 |
| 存储 | 直接存储数值本身。 | 在堆内存中创建对象,对象内部存储一个 int 类型的值。 |
| 默认值 | 0 |
null (非常重要!) |
| 方法 | 没有,不能调用任何方法。 | 有很多静态方法和实例方法,如 parseInt(), toString(), compareTo() 等。 |
| 集合支持 | 不能直接放入 ArrayList, HashMap 等集合中,集合只能存对象。 |
可以直接放入集合中。 |
| 性能 | 占用内存小,计算速度快。 | 占用内存大(对象头 + 数据),创建和销毁有额外开销。 |
| 装箱/拆箱 | - | 支持自动装箱 和 自动拆箱。 |
| 大小 | 固定大小,为 32 位,有范围限制 (-2^31 到 2^31-1)。 |
大小不固定,取决于 JVM 和对象,但远大于 int。 |
深入解析
int - 原始类型
int 是 Java 八种基本数据类型之一,它就像一个最简单的数字标签,用来表示整数。
特点:
- 高效:因为直接在栈上分配内存,没有对象的开销,所以计算速度非常快。
- 简单:它只有值,没有行为(方法)。
示例:
int age = 30; // 在栈上分配空间,直接存储值 30 age = age + 1; // 直接对值进行操作 // age.toString(); // 编译错误!int 没有方法
Integer - 包装类
Integer 类是为了让 int 这种基本类型也能以“对象”的形式存在而设计的,这在面向对象的编程中非常有用。
为什么需要包装类?
- 面向对象:Java 是一门面向对象的语言,很多核心功能(如集合框架)都要求操作的是对象,而不是基本类型。
- 提供实用方法:
Integer类提供了很多静态方法来处理int类型,Integer.parseInt("123"): 将字符串 "123" 转换为int类型的 123。Integer.toString(123): 将int类型的 123 转换为字符串 "123"。Integer.compare(a, b): 比较两个整数的大小。
- 支持
null值:Integer可以是null,这在某些场景下非常有用,可以表示“无值”或“未知”,而int必须有值,其默认值是0,这可能导致混淆(0是一个有效的值,还是表示“未初始化”?)。
示例:
Integer score = new Integer(100); // 显式创建对象 (旧方式,不推荐) Integer score = 100; // 自动装箱,现代 Java 推荐写法 // 使用 Integer 的方法 String strScore = score.toString(); // "100" int primitiveScore = score; // 自动拆箱,将 Integer 对象转换回 int 值 // 在集合中使用 List<Integer> scores = new ArrayList<>(); scores.add(95); // 自动装箱,95 被包装成 Integer 对象后存入
核心概念:自动装箱与自动拆箱
这是 Java 5 引入的一个非常方便的特性,它让 int 和 Integer 之间的转换变得透明,由编译器自动完成。
自动装箱
当一个 int 类型的值需要被赋给一个 Integer 类型的引用变量时,编译器会自动调用 Integer.valueOf() 方法,将其包装成一个 Integer 对象。
// 编译器看到的代码 Integer i = 10; // 编译器实际生成的代码 (类似这样) Integer i = Integer.valueOf(10);
自动拆箱
当一个 Integer 对象需要被用在需要一个 int 类型的地方时(如算术运算、赋值给 int 变量),编译器会自动调用 Integer.intValue() 方法,将其拆箱为 int 值。
// 编译器看到的代码 Integer i = 10; int j = i + 5; // i 被自动拆箱 // 编译器实际生成的代码 (类似这样) Integer i = Integer.valueOf(10); int j = i.intValue() + 5;
自动装箱/拆箱的陷阱
这个“自动化”的特性也带来了一些容易出错的地方。
陷阱 1:NullPointerException
由于自动拆箱,Integer 对象是 null,那么在尝试将其转换为 int 时,就会抛出 NullPointerException。
Integer count = null; int primitiveCount = count; // 抛出 NullPointerException! // 因为编译器会尝试执行 count.intValue(),而 null 对象没有 intValue() 方法。
陷阱 2:性能问题与对象缓存
Integer 的 valueOf() 方法对 -128 到 127 之间的值做了缓存,这意味着:
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 不在缓存范围内,创建了两个新对象
注意: 比较的是对象的内存地址,对于 Integer,只有指向同一个对象时才为 true,要比较 Integer 对象中包裹的 int 值是否相等,应该使用 equals() 方法:
Integer x = 128; Integer y = 128; System.out.println(x.equals(y)); // 输出 true,比较的是值
选择使用 int 还是 Integer?
这是一个非常实际的问题。
| 场景 | 推荐使用 | 原因 |
|---|---|---|
| 局部变量、方法参数、循环计数器 | int |
性能高,内存占用小,是绝大多数情况下的最佳选择。 |
| 需要表示“无值”或“未知” | Integer |
Integer 可以是 null,而 int 不能,数据库查询可能返回某个值,也可能为空。 |
| 需要存入集合框架 | Integer |
List, Set, Map 等集合只能存储对象。 |
需要调用 Integer 类的方法 |
Integer |
如 parseInt, toString, bitCount 等。 |
| 在泛型中使用 | Integer |
泛型类型参数(如 T)必须是对象类型,不能是基本类型。 |
int是高效的、底层的数值工具,用于所有不需要对象特性的计算场景。Integer是面向对象的“外衣”,它让int能够融入对象世界(如集合),并提供了丰富的工具方法,同时支持null来表达“无”的概念。- 自动装箱/拆箱 是一座便利的桥梁,但开发者必须了解其背后的机制和潜在陷阱(如
NullPointerException和缓存问题)。
理解这两者的区别,是迈向 Java 中高级开发的关键一步。
