Java反射获取属性的几种实现方式
获取所有公共属性(包括继承的)
import java.lang.reflect.Field;
public class ReflectionExample {
public static void main(String[] args) {
try {
// 获取Class对象
Class<?> clazz = Class.forName("com.example.User");
// 获取所有公共属性(包括继承的)
Field[] fields = clazz.getFields();
System.out.println("所有公共属性:");
for (Field field : fields) {
System.out.println("属性名: " + field.getName() +
", 类型: " + field.getType().getName());
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
获取所有声明的属性(不包括继承的)
public class ReflectionExample2 {
public static void main(String[] args) {
Class<?> clazz = User.class;
// 获取所有声明的属性(包括private,但不包括继承的)
Field[] declaredFields = clazz.getDeclaredFields();
System.out.println("所有声明的属性:");
for (Field field : declaredFields) {
System.out.println("属性名: " + field.getName() +
", 修饰符: " + Modifier.toString(field.getModifiers()) +
", 类型: " + field.getType().getSimpleName());
}
}
}
// 示例类
class User {
public String name;
private int age;
protected String email;
String address; // 默认访问权限
public static final String TYPE = "USER";
}
获取单个属性并操作
public class ReflectionExample3 {
public static void main(String[] args) throws Exception {
// 创建对象实例
User user = new User("张三", 25);
// 获取Class对象
Class<?> clazz = user.getClass();
// 获取指定属性
Field nameField = clazz.getField("name"); // 获取公共属性
Field ageField = clazz.getDeclaredField("age"); // 获取声明属性(包括私有)
// 访问私有属性时需要设置可访问
ageField.setAccessible(true);
// 获取属性值
String name = (String) nameField.get(user);
int age = (int) ageField.get(user);
System.out.println("修改前 - name: " + name + ", age: " + age);
// 修改属性值
nameField.set(user, "李四");
ageField.set(user, 30);
System.out.println("修改后 - name: " + user.getName() + ", age: " + user.getAge());
}
}
class User {
public String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() { return name; }
public int getAge() { return age; }
}
获取属性的完整信息
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class ReflectionExample4 {
public static void main(String[] args) throws Exception {
Class<?> clazz = User.class;
// 获取所有属性
Field[] fields = clazz.getDeclaredFields();
System.out.println("属性详细信息:");
for (Field field : fields) {
System.out.println("\n属性名: " + field.getName());
System.out.println("类型: " + field.getType().getName());
System.out.println("修饰符: " + Modifier.toString(field.getModifiers()));
// 获取注解
Annotation[] annotations = field.getAnnotations();
if (annotations.length > 0) {
System.out.println("注解: ");
for (Annotation annotation : annotations) {
System.out.println(" - " + annotation.annotationType().getName());
}
}
// 获取泛型类型(如果有)
Type genericType = field.getGenericType();
if (genericType instanceof ParameterizedType) {
ParameterizedType paramType = (ParameterizedType) genericType;
Type[] actualTypes = paramType.getActualTypeArguments();
System.out.println("泛型参数: ");
for (Type type : actualTypes) {
System.out.println(" - " + type.getTypeName());
}
}
}
}
}
// 带注解和泛型的示例类
class Person {
@Deprecated
public String name;
public List<String> tags;
private Map<String, Integer> scores;
// ...
}
实用工具方法
public class ReflectionUtils {
/**
* 获取对象的所有字段名和值
*/
public static Map<String, Object> getAllFields(Object obj) throws Exception {
Map<String, Object> result = new HashMap<>();
Class<?> clazz = obj.getClass();
// 获取包括父类的所有字段
while (clazz != null) {
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
result.put(field.getName(), field.get(obj));
}
clazz = clazz.getSuperclass(); // 向上查找父类
}
return result;
}
/**
* 复制对象属性
*/
public static void copyFields(Object source, Object target) throws Exception {
Class<?> sourceClass = source.getClass();
Class<?> targetClass = target.getClass();
Field[] sourceFields = sourceClass.getDeclaredFields();
for (Field sourceField : sourceFields) {
sourceField.setAccessible(true);
try {
Field targetField = targetClass.getDeclaredField(sourceField.getName());
if (targetField.getType().equals(sourceField.getType())) {
targetField.setAccessible(true);
targetField.set(target, sourceField.get(source));
}
} catch (NoSuchFieldException e) {
// 目标对象没有该字段,跳过
}
}
}
}
注意事项
- 性能问题:反射操作比直接访问属性慢,频繁使用时需要考虑性能优化
- 安全检查:访问私有属性时需要调用
setAccessible(true) - 异常处理:反射操作会抛出多种异常,需要适当处理
- 类型安全:反射绕过了编译时的类型检查,需要注意类型转换
- 线程安全:反射操作可能不是线程安全的
这些示例覆盖了Java反射获取属性的主要场景,可以根据实际需求选择合适的方式。
