475. Java 反射 - 处理基本类型字段
在 Java 中,基本类型(primitive types) 和 包装类型(wrapper types) 是两个不同的概念,但反射操作 Field.get() 和 Field.set() 都是基于 Object 类型的,这意味着:
- 读取基本类型字段时,返回值会被 自动装箱(boxing)为对应的包装类型。
- 设置基本类型字段时,传入的值需要是包装类型(如
Integer、Double等),再由 JVM 自动拆箱(unboxing)。
1. 常规做法:通过 get() / set()
class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
}
读取字段:
User maria = new User("Maria", 32);
Class<?> userClass = User.class;
Field ageField = userClass.getDeclaredField("age");
ageField.setAccessible(true);
Object ageObj = ageField.get(maria); // 返回 Object
int age = (Integer) ageObj; // 需要强制转换
System.out.println("age = " + age);
修改字段:
ageField.set(maria, 33); // 自动装箱 Integer → int
2. 高效做法:使用专用的 get/set 方法
反射 API 提供了专门针对基本类型的 getXxx() 和 setXxx() 方法,避免了装箱/拆箱开销:
-
getInt(Object obj)/setInt(Object obj, int value) -
getBoolean()/setBoolean() -
getDouble()/setDouble() - …(所有 8 种基本类型都支持)
示例
User maria = new User("Maria", 32);
Field ageField = User.class.getDeclaredField("age");
ageField.setAccessible(true);
int age = ageField.getInt(maria);
System.out.println("age = " + age);
ageField.setInt(maria, 33);
age = ageField.getInt(maria);
System.out.println("age = " + age);
输出
age = 32
age = 33
✅ 优点:避免了 int ↔ Integer 的装箱/拆箱,性能更高。
3. 注意事项:类型必须匹配
如果字段类型和调用的方法不一致,会抛出异常。
示例:将 age 从 int 改为 Integer
class User {
private String name;
private Integer age;
}
仍然用 getInt() 访问:
int age = ageField.getInt(maria);
会报错:
Exception in thread "main" java.lang.IllegalArgumentException:
Attempt to get java.lang.Integer field "User.age" with illegal data type conversion to int
⚠️ 结论:
- 基本类型字段 → 使用
getInt()/setInt()等专用方法。 - 包装类型字段 → 只能用
get()/set(),并进行强制类型转换。
4. 总结
-
通用方法:
-
get()/set(),适用于所有字段,但需要强转,并且会有装箱/拆箱开销。
-
-
专用方法:
-
getInt()/setInt()等,适用于基本类型,性能更好。
-
-
易错点:
- 调用专用方法时必须与字段类型完全匹配,否则会抛异常。