Java 包装类(Wrapper Class)详解
一、什么是包装类
包装类是将基本数据类型封装成对象的类,使基本数据类型具备对象的特性。
┌─────────────────────────────────────────────────────────────┐
│ 基本数据类型 vs 包装类 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 基本数据类型 包装类 │
│ ┌─────────┐ ┌─────────────┐ │
│ │ int │ ←→ │ Integer │ │
│ │ 1 │ 装箱 │ new Integer │ │
│ │ │ 拆箱 │ (value: 1) │ │
│ └─────────┘ └─────────────┘ │
│ │
│ 简单值,无属性无方法 对象,有属性有方法 │
│ │
└─────────────────────────────────────────────────────────────┘二、八种包装类一览
| 基本数据类型 | 包装类 | 父类 |
|---|---|---|
byte | Byte | Number |
short | Short | Number |
int | Integer | Number |
long | Long | Number |
float | Float | Number |
double | Double | Number |
char | Character | Object |
boolean | Boolean | Object |
对应关系速记
byte → Byte
short → Short
int → Integer (特殊:不是 Int)
long → Long
float → Float
double → Double
char → Character (特殊:不是 Char)
boolean → Boolean三、继承关系图
Object
│
│
┌─────────┴─────────┐
│ │
Character Boolean
│ │
│ │
▼ ▼
Number ◄────────────┐
│ │
┌────────┴───┬───┬──────┴──────┐
│ │ │ │
▼ ▼ ▼ ▼
Byte Short Integer Long
┌───┬───┘
▼ ▼
Float Double四、创建方式
1. 构造方法创建(已过时,不推荐)
java
// Integer 构造方法
Integer i1 = new Integer(100); // 已过时 ❌
Integer i2 = new Integer("100"); // 已过时 ❌
// Double 构造方法
Double d1 = new Double(3.14); // 已过时 ❌
Double d2 = new Double("3.14"); // 已过时 ❌
// Boolean 构造方法
Boolean b1 = new Boolean(true); // 已过时 ❌
Boolean b2 = new Boolean("true"); // 已过时 ❌
Boolean b3 = new Boolean("abc"); // 已过时 ❌ → false2. valueOf() 静态方法(推荐)
java
// Integer
Integer i1 = Integer.valueOf(100); // int → Integer
Integer i2 = Integer.valueOf("100"); // String → Integer
Integer i3 = Integer.valueOf("100", 2); // 二进制字符串 → Integer
// Double
Double d1 = Double.valueOf(3.14);
// Boolean
Boolean b1 = Boolean.valueOf(true);
Boolean b2 = Boolean.valueOf("true"); // "true" → true
Boolean b3 = Boolean.valueOf("TRUE"); // 不区分大小写 → true
Boolean b4 = Boolean.valueOf("abc"); // → false3. 自动装箱(推荐)
java
// 编译器自动转换:int → Integer
Integer i1 = 100; // 自动装箱
Integer i2 = 100; // 自动装箱
Double d1 = 3.14; // 自动装箱
Boolean b1 = true; // 自动装箱五、自动装箱与拆箱
概念
┌─────────────────────────────────────────────────────────────┐
│ │
│ 装箱 (Boxing) 拆箱 (Unboxing) │
│ ───────────── ────────────── │
│ 基本类型 → 对象 对象 → 基本类型 │
│ int → Integer Integer → int │
│ │
│ 100 ────────→ Integer(100) │
│ 装箱 Integer(100) ────────→ 100 │
│ │
└─────────────────────────────────────────────────────────────┘自动装箱源码原理
java
// 编译器自动转换
Integer i = 100;
// 实际转换为
Integer i = Integer.valueOf(100);自动拆箱源码原理
java
// 编译器自动转换
Integer i = 100;
int num = i + 50;
// 实际转换为
Integer i = Integer.valueOf(100);
int num = i.intValue() + 50; // 调用 intValue() 拆箱完整示例
java
// ┌─────────────────────────────────────────────────────────┐
// │ 自动装箱:基本类型 → 包装类 │
// └─────────────────────────────────────────────────────────┘
// 写法1:直接赋值(推荐)
Integer i1 = 100;
// 写法2:自动装箱
Integer i2 = Integer.valueOf(100);
// 写法3:显式装箱(已过时)
Integer i3 = new Integer(100);
// ┌─────────────────────────────────────────────────────────┐
// │ 自动拆箱:包装类 → 基本类型 │
// └─────────────────────────────────────────────────────────┘
Integer i = 100;
// 写法1:直接运算(推荐)
int num1 = i + 50; // 自动拆箱
// 写法2:显式拆箱
int num2 = i.intValue(); // 调用方法拆箱
// ┌─────────────────────────────────────────────────────────┐
// │ 混合运算 │
// └─────────────────────────────────────────────────────────┘
Integer a = 10;
Integer b = 20;
Integer c = a + b; // a拆箱 → 相加 → 结果装箱 → c六、面试重点:Integer 缓存机制
核心规则
Integer 缓存范围:-128 ~ 127
java
Integer i1 = 127;
Integer i2 = 127;
System.out.println(i1 == i2); // true ← 同一对象
Integer i3 = 128;
Integer i4 = 128;
System.out.println(i3 == i4); // false ← 不同对象源码解析
java
// Integer.valueOf() 源码
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
// IntegerCache 缓存范围
// low = -128
// high = 127 (可配置)图解
┌─────────────────────────────────────────────────────────────┐
│ Integer 缓存池 │
├─────────────────────────────────────────────────────────────┤
│ │
│ IntegerCache.cache[] │
│ ┌─────┬─────┬─────┬─────┬───┬─────┬─────┬─────┐ │
│ │-128 │-127 │-126 │-125 │...│ 126 │ 127 │ │ │
│ └──┬──┴──┬──┴──┬──┴──┬─┘ └──┬──┴──┬──┴─────┘ │
│ │ │ │ │ │ │ │
│ ▼ ▼ ▼ ▼ ▼ ▼ │
│ ┌─────┬─────┬─────┬─────┬───┬─────┬─────┐ │
│ │127个│ │ │ │...│ │127个│ 复用缓存对象 │
│ │对象 │ │ │ │ │ │对象 │ │
│ └─────┴─────┴─────┴─────┴───┴─────┴─────┘ │
│ │
│ ┌──────────────────────────────────────────┐ │
│ │ i >= -128 && i <= 127 → 返回缓存对象 │ │
│ │ i < -128 || i > 127 → new Integer() │ │
│ └──────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘面试题讲解
java
// 题目1
Integer a = 100;
Integer b = 100;
System.out.println(a == b); // true
// 原因:100 在缓存范围内,使用同一个对象
// 题目2
Integer c = 200;
Integer d = 200;
System.out.println(c == d); // false
// 原因:200 超出缓存范围,每次创建新对象
// 题目3
Integer e = 100;
int f = 100;
System.out.println(e == f); // true
// 原因:e 自动拆箱成 int,再与 f 比较
// 题目4
Integer g = new Integer(100);
Integer h = new Integer(100);
System.out.println(g == h); // false
// 原因:new Integer() 每次都创建新对象
// 题目5
Integer i = 100;
Integer j = Integer.valueOf(100);
System.out.println(i == j); // true
// 原因:valueOf(100) 返回缓存对象,i 也是缓存对象其他包装类的缓存
| 包装类 | 缓存范围 | 说明 |
|---|---|---|
Byte | -128 ~ 127 | 所有字节都缓存 |
Short | -128 ~ 127 | 同 Integer |
Integer | -128 ~ 127 | 可通过 -Djava.lang.Integer.IntegerCache.high=xxx 配置 |
Long | -128 ~ 127 | 同 Integer |
Float | 无缓存 | 每次 new |
Double | 无缓存 | 每次 new |
Character | 0 ~ 127 | ASCII 字符缓存 |
Boolean | true/false | 静态常量 TRUE/FALSE |
java
// Character 缓存示例
Character c1 = 127; // 自动装箱,返回缓存对象
Character c2 = 127;
System.out.println(c1 == c2); // true
Character c3 = 128; // 超出范围,new 新对象
Character c4 = 128;
System.out.println(c3 == c4); // false七、常用方法
1. 类型转换方法
java
// ┌─────────────────────────────────────────────────────────┐
// │ String → 基本类型(推荐) │
// └─────────────────────────────────────────────────────────┘
int i = Integer.parseInt("100"); // "100" → 100
long l = Long.parseLong("100"); // "100" → 100L
double d = Double.parseDouble("3.14"); // "3.14" → 3.14
boolean b = Boolean.parseBoolean("true"); // "true" → true
// ┌─────────────────────────────────────────────────────────┐
// │ String → 包装类 │
// └─────────────────────────────────────────────────────────┘
Integer i = Integer.parseInt("100"); // 返回基本类型
Integer i2 = Integer.valueOf("100"); // 返回包装类
// ┌─────────────────────────────────────────────────────────┐
// │ 基本类型 → String │
// └─────────────────────────────────────────────────────────┘
String s1 = String.valueOf(100); // 100 → "100"
String s2 = 100 + ""; // 100 → "100"
String s3 = Integer.toString(100); // 100 → "100"
// ┌─────────────────────────────────────────────────────────┐
// │ 包装类 → 基本类型 │
// └─────────────────────────────────────────────────────────┘
Integer i = new Integer("100");
int num = i.intValue(); // Integer → int
long l = i.longValue(); // Integer → long
double d = i.doubleValue(); // Integer → double
// ┌─────────────────────────────────────────────────────────┐
// │ 自动拆箱:包装类 → 基本类型(推荐) │
// └─────────────────────────────────────────────────────────┘
Integer i = 100;
int num = i; // 自动拆箱2. 进制转换方法
java
// ┌─────────────────────────────────────────────────────────┐
// │ 十进制 → 其他进制 │
// └─────────────────────────────────────────────────────────┘
String binary = Integer.toBinaryString(10); // 10 → "1010" (二进制)
String octal = Integer.toOctalString(10); // 10 → "12" (八进制)
String hex = Integer.toHexString(10); // 10 → "a" (十六进制)
String hexUpper = Integer.toHexString(255).toUpperCase(); // "FF"
// ┌─────────────────────────────────────────────────────────┐
// │ 其他进制 → 十进制 │
// └─────────────────────────────────────────────────────────┘
int dec1 = Integer.parseInt("1010", 2); // 二进制"1010" → 10
int dec2 = Integer.parseInt("12", 8); // 八进制"12" → 10
int dec3 = Integer.parseInt("a", 16); // 十六进制"a" → 10
int dec4 = Integer.parseInt("A", 16); // 十六进制"A" → 10
// ┌─────────────────────────────────────────────────────────┐
// │ 其他进制 → 其他进制 │
// └─────────────────────────────────────────────────────────┘
// 二进制 → 十六进制
String binToHex = Long.toHexString(Long.parseLong("1010", 2));
// 或
String result = Integer.toHexString(Integer.parseInt("1010", 2));3. 常用常量
java
// Integer
System.out.println(Integer.MAX_VALUE); // 2147483647
System.out.println(Integer.MIN_VALUE); // -2147483648
System.out.println(Integer.SIZE); // 32 (位数)
System.out.println(Integer.BYTES); // 4 (字节数)
// Long
System.out.println(Long.MAX_VALUE); // 9223372036854775807
System.out.println(Long.MIN_VALUE); // -9223372036854775808
// Double
System.out.println(Double.MAX_VALUE); // 1.7976931348623157E308
System.out.println(Double.MIN_VALUE); // 4.9E-324
// Character
System.out.println(Character.MAX_VALUE); // '\uffff'
System.out.println(Character.MIN_VALUE); // '\u0000'
System.out.println(Character.isDigit('3')); // true
System.out.println(Character.isLetter('A')); // true
System.out.println(Character.isUpperCase('a')); // false4. 比较方法
java
// ┌─────────────────────────────────────────────────────────┐
// │ compareTo(实现 Comparable 接口) │
// └─────────────────────────────────────────────────────────┘
Integer a = 10;
Integer b = 20;
System.out.println(a.compareTo(b)); // -1 (a < b)
System.out.println(b.compareTo(a)); // 1 (b > a)
System.out.println(a.compareTo(10)); // 0 (相等)
// ┌─────────────────────────────────────────────────────────┐
// │ compare(静态方法,用于排序) │
// └─────────────────────────────────────────────────────────┘
System.out.println(Integer.compare(10, 20)); // -1
System.out.println(Integer.compare(20, 10)); // 1
System.out.println(Integer.compare(10, 10)); // 0
// ┌─────────────────────────────────────────────────────────┐
// │ equals(比较值是否相等) │
// └─────────────────────────────────────────────────────────┘
Integer a = new Integer(100);
Integer b = new Integer(100);
System.out.println(a == b); // false (引用比较)
System.out.println(a.equals(b)); // true (值比较)
// ┌─────────────────────────────────────────────────────────┐
// │ 特别注意:equals 与 == 在自动装箱时的表现 │
// └─────────────────────────────────────────────────────────┘
Integer a = 127;
Integer b = 127;
System.out.println(a == b); // true (缓存)
System.out.println(a.equals(b)); // true (值相等)
Integer c = 128;
Integer d = 128;
System.out.println(c == d); // false (非缓存)
System.out.println(c.equals(d)); // true (值相等)八、基本类型 vs 包装类
区别汇总
| 特性 | 基本数据类型 | 包装类 |
|---|---|---|
| 默认值 | 有默认值(如 0) | 默认值是 null |
| 存储位置 | 栈(局部变量) | 堆(对象) |
| 泛型支持 | 不支持 | 支持 |
| 方法调用 | 不能调用方法 | 可以调用各种方法 |
| 内存效率 | 高(直接存值) | 低(需要对象开销) |
| 比较方式 | == 比较值 | == 比较引用,equals 比较值 |
代码示例
java
// 1. 默认值
int i = 0; // 正确,int 默认值就是 0
Integer ii = null; // 正确,引用类型默认 null
// Integer iii; // 错误!局部变量必须初始化
// 2. 泛型支持
List<int> list1; // ❌ 错误!基本类型不能用于泛型
List<Integer> list2; // ✅ 正确
// 3. 方法调用
int num = 100;
num.toString(); // ❌ 错误!基本类型不能调用方法
Integer n = 100;
n.toString(); // ✅ "100"
n.MAX_VALUE; // ✅ 可以访问静态常量
n.compareTo(50); // ✅ 可以调用实例方法
// 4. 集合操作
List<int> nums1 = new ArrayList<>(); // ❌ 编译错误
List<Integer> nums2 = new ArrayList<>(); // ✅ 正确
nums2.add(100); // 自动装箱
int value = nums2.get(0); // 自动拆箱九、应用场景
1. 集合框架
java
// List:只能存储对象,不能存基本类型
List<Integer> list = new ArrayList<>();
list.add(1); // 自动装箱:1 → Integer(1)
list.add(2); // 自动装箱:2 → Integer(2)
int num = list.get(0); // 自动拆箱:Integer(1) → 1
// Map:键值对
Map<String, Integer> map = new HashMap<>();
map.put("age", 25); // 自动装箱
// Set:去重
Set<Integer> set = new HashSet<>();
set.add(100);
set.add(100); // 重复添加无效2. 类型转换
java
// 字符串解析为数字
String input = "123";
int num = Integer.parseInt(input);
double price = Double.parseDouble("19.99");
// 数字转字符串
int age = 25;
String s1 = String.valueOf(age);
String s2 = age + "";
String s3 = Integer.toString(age);
// 进制转换
String bin = Integer.toBinaryString(10);
int dec = Integer.parseInt("1010", 2);3. 方法返回值
java
// 返回 null 表示特殊情况
public Integer findAge(String name) {
if ("Tom".equals(name)) {
return 25;
}
return null; // 基本类型 int 无法表示"未找到"
}
// 区别于
public int findAge2(String name) {
if ("Tom".equals(name)) {
return 25;
}
return -1; // 必须返回一个"特殊"值
}4. 反射和泛型
java
// 反射获取字段值(返回 Object,需强转)
Field field = person.getClass().getDeclaredField("age");
Object value = field.get(person);
int age = (Integer) value;
// 泛型必须用包装类
class Result<T> {
private T data;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
Result<Integer> intResult = new Result<>(); // ✅
Result<int> intResult2; // ❌5. 数据库操作
java
// MyBatis / Hibernate 查询结果
// 数据库 NULL → 包装类 null
Integer age = jdbcTemplate.queryForObject(
"SELECT age FROM user WHERE id = ?",
Integer.class,
userId
);
if (age == null) {
System.out.println("用户未设置年龄");
} else {
System.out.println("年龄: " + age);
}十、常见面试题
题目1:Integer 缓存
java
Integer a = 1;
Integer b = 2;
Integer c = 3;
Integer d = 3;
Integer e = 321;
Integer f = 321;
Long g = 3L;
Long h = 2L;
// 问:下面表达式的结果?
System.out.println(c == d); // ?
System.out.println(e == f); // ?
System.out.println(c == (a + b)); // ?
System.out.println(c.equals(a + b)); // ?
System.out.println(g == (a + b)); // ?
System.out.println(g.equals(a + b)); // ?答案:
java
System.out.println(c == d); // true (缓存)
System.out.println(e == f); // false (超出缓存)
System.out.println(c == (a + b)); // true (运算时自动拆箱)
System.out.println(c.equals(a + b)); // true (equals 比较值)
System.out.println(g == (a + b)); // true (类型提升,结果是 long)
System.out.println(g.equals(a + b)); // false (类型不同,false)题目2:运算时的自动拆箱
java
Integer i = new Integer(1);
i = null;
int j = i; // NullPointerException!
// 等价于:int j = i.intValue();
// i 是 null,无法调用方法题目3:Double vs Integer
java
Double d1 = 0.1;
Double d2 = 0.1;
System.out.println(d1 == d2); // false (Double 无缓存)
Integer i1 = 0;
Integer i2 = 0;
System.out.println(i1 == i2); // true (Integer 有缓存)十一、总结
一句话记忆
包装类 = 基本类型 + 对象特性(可以 null、可以调用方法、可以用于泛型)
使用建议
| 场景 | 推荐 | 原因 |
|---|---|---|
| 集合存储 | 包装类 | 基本类型不能存集合 |
| 数据库映射 | 包装类 | 支持 NULL |
| 数值运算 | 基本类型 | 性能更好,无空指针风险 |
| 泛型 | 包装类 | 基本类型不支持泛型 |
| 方法参数可为空 | 包装类 | 用 null 表示特殊情况 |
速查表
| 需求 | 代码 |
|---|---|
| String → int | int i = Integer.parseInt("100"); |
| int → String | String s = String.valueOf(100); |
| String → Integer | Integer i = Integer.valueOf("100"); |
| int → Integer | Integer i = 100; 或 Integer.valueOf(100) |
| Integer → int | int i = i1; 或 i1.intValue() |
| 判断是否为数字 | Character.isDigit(ch) |
| 获取最大值 | Integer.MAX_VALUE |
相关标签
#Java #包装类 #Integer #自动装箱 #自动拆箱 #缓存机制