通过反射获取类和父类的属性和属性值

本文介绍如何使用Java反射机制递归地获取一个类及其父类的所有私有属性,并将这些属性封装到SensorData类中。通过具体实例演示了如何实现这一过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

通过反射我们可以获取到一个类的属性和方法,但获取父类的private的属性却不可以直接获取,需要递归调用superclass来获取属性


SuperClass.java

public class SuperClass {

	private String name;
	private String age;
	private Date birthday;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getAge() {
		return age;
	}

	public void setAge(String age) {
		this.age = age;
	}

	public Date getBirthday() {
		return birthday;
	}

	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}

}


SubClass.java

public class SubClass extends SuperClass {
	private String sid;

	public String getSid() {
		return sid;
	}

	public void setSid(String sid) {
		this.sid = sid;
	}

}

SubSubClass.java

public class SubSubClass extends SubClass {
	private String grade;

	public String getGrade() {
		return grade;
	}

	public void setGrade(String grade) {
		this.grade = grade;
	}

}

保存属性和属性值

SensorData.java

public class SensorData {
    private String  sensorId;
    private Object sensorValue;

    public String getSensorId() {
        return sensorId;
    }

    public void setSensorId(String sensorId) {
        this.sensorId = sensorId;
    }

    public Object getSensorValue() {
        return sensorValue;
    }

    public void setSensorValue(Object sensorValue) {
        this.sensorValue = sensorValue;
    }

	@Override
	public String toString() {
		return "SensorData [sensorId=" + sensorId + ", sensorValue=" + sensorValue + "]";
	}
    
    
}

TestRe.java 测试类

public class TestRe {
	
	public static void main(String[] args) {
		SuperClass cla =new SubSubClass();
		//SuperClass cla =new SubClass();
		
		List<SensorData>  s = sensorDataList(cla);
		for(SensorData ss :s){
			System.out.println(ss);
		}
	}
	
	/**
	 * 通过反射获取各个属性名称和属性值封装成类
	 * 
	 * @param sensorDataDto
	 * @return
	 */
	public static List<SensorData> sensorDataList(Object sensorDataDto) {
		List<SensorData> sensorDatas = new ArrayList<SensorData>();
		Class<?> clazz = sensorDataDto.getClass();
		try {
			exceClass(sensorDataDto, sensorDatas, clazz);
		} catch (Exception e) {

		}
		return sensorDatas;
	}

	private static void exceClass(Object sensorDataDto, List<SensorData> sensorDatas, Class<?> clazz) throws Exception {
		if (clazz != Object.class) {
			System.out.println(clazz);
			returnclassF(sensorDataDto, sensorDatas, clazz);
			Class<?> clazzs = clazz.getSuperclass();
			exceClass(sensorDataDto, sensorDatas, clazzs);
		}
	}

	private static void returnclassF(Object sensorDataDto, List<SensorData> sensorDatas, Class<?> clazz) throws Exception {
		Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields) {
			field.setAccessible(true);
			SensorData sensorData = new SensorData();
			sensorData.setSensorId(field.getName().toString());
			sensorData.setSensorValue(field.get(sensorDataDto));
			sensorDatas.add(sensorData);
		}
	}
}



通过
class com.ref.SubSubClass
class com.ref.SubClass
class com.ref.SuperClass
SensorData [sensorId=grade, sensorValue=null]
SensorData [sensorId=sid, sensorValue=null]
SensorData [sensorId=name, sensorValue=null]
SensorData [sensorId=age, sensorValue=null]
SensorData [sensorId=birthday, sensorValue=null]


通过多态可以获取不同类的属性和值

class com.ref.SubClass
class com.ref.SuperClass
SensorData [sensorId=sid, sensorValue=null]
SensorData [sensorId=name, sensorValue=null]
SensorData [sensorId=age, sensorValue=null]
SensorData [sensorId=birthday, sensorValue=null]


<think>我们正在解决如何通过反射获取JavaBean父类的字段(Field)的问题。根据引用[2]引用[3]提到的问题:当尝试通过子获取父类的字段时,直接使用`getDeclaredField`会抛出`NoSuchFieldException`,因为`getDeclaredField`只能获取当前声明的字段(不包括父类)。因此,我们需要递归地向上遍历父类,直到找到指定的字段。步骤:1.从当前开始,尝试获取字段。2.如果当前没有找到,则获取父类,并在父类中继续查找。3.重复步骤2直到找到字段或到达`Object`(即没有父类)为止。注意:根据引用[1]中的方法,我们可以使用`getDeclaredField`来获取中声明的字段(包括私有字段),但是要获取父类的字段,我们需要在父类上调用该方法。具体实现如下:</think>### 使用反射获取 Java Bean 父类字段的完整指南 #### 核心问题分析 当使用反射获取父类字段时,直接调用 `clazz.getDeclaredField("id")` 会抛出 `NoSuchFieldException`[^2]。这是因为: - `getDeclaredField()` 只能获取当前声明的字段 - `getField()` 只能获取当前的公有字段(包括继承的公有字段) - **父类的私有/受保护字段**需通过递归查找父类获取 #### 递归获取父类字段的解决方案 ```java public static Field getFieldIncludingSuperclasses(Class<?> clazz, String fieldName) throws NoSuchFieldException { // 从当前开始向上递归查找 Class<?> currentClass = clazz; while (currentClass != null && currentClass != Object.class) { try { // 尝试获取当前的字段(包括私有字段) Field field = currentClass.getDeclaredField(fieldName); field.setAccessible(true); // 解除访问限制 return field; } catch (NoSuchFieldException e) { // 当前未找到,继续查找父类 currentClass = currentClass.getSuperclass(); } } throw new NoSuchFieldException(fieldName + " 在及其父类中不存在"); } ``` #### 使用示例 ```java class Parent { private Long id; // 父类私有字段 } class Child extends Parent { private String name; } public static void main(String[] args) throws Exception { Child child = new Child(); // 获取父类的 id 字段 Field idField = getFieldIncludingSuperclasses(Child.class, "id"); // 设置字段值 idField.set(child, 10001L); // 获取字段值 System.out.println("父类ID: " + idField.get(child)); // 输出: 父类ID: 10001 } ``` #### 关键说明 1. **访问权限处理** `field.setAccessible(true)` 可突破 `private/protected` 访问限制[^1],但需注意: ```java // 安全管理器可能阻止此操作,需添加JVM参数 --add-opens java.base/java.lang.reflect=ALL-UNNAMED ``` 2. **字段继承关系** - 父类公有字段可直接通过 `child.getClass().getField("id")` 获取 - 父类私有字段必须通过递归查找父类获取 3. **获取字段信息** ```java // 获取字段Class<?> fieldType = idField.getType(); // 返回 Long.class // 获取字段修饰符 int modifiers = idField.getModifiers(); boolean isPrivate = Modifier.isPrivate(modifiers); ``` #### 常见错误处理 | 错误型 | 原因 | 解决方案 | |---------|------|---------| | `NoSuchFieldException` | 字段不存在于父类中 | 检查字段名拼写或确认继承关系 | | `IllegalAccessException` | 未调用 `setAccessible(true)` | 在操作字段前解除访问限制 | | `NullPointerException` | 传入的 `obj` 实例为 `null` | 确保操作非静态字段时提供有效对象 | #### 获取父类字段注解 通过反射获取字段上的注解信息[^4]: ```java // 获取字段上的特定注解 Id annotation = idField.getAnnotation(Id.class); if (annotation != null) { System.out.println("ID生成策略: " + annotation.generationType()); } // 获取所有注解 Annotation[] annotations = idField.getAnnotations(); ``` > **性能提示**:递归查找父类字段较耗时,建议缓存结果: > ```java > private static final Map<ClassFieldKey, Field> FIELD_CACHE = new ConcurrentHashMap<>(); > > // 使用+字段名作为复合键 > record ClassFieldKey(Class<?> clazz, String fieldName) {} > ``` --- ### 相关问题 1. 如何通过反射修改父类中的 `final` 字段值? 2. 获取父类字段时如何处理不同包下的受保护(`protected`)字段? 3. 如何递归获取及其父类的所有字段列表? 4. 反射操作父类字段时如何避免破坏封装性? 5. 在 Spring 框架中如何优雅地实现父类字段注入? [^1]: Java 反射获取实体字段值 [^2]: java 反射获取父类的字段字: NoSuchFieldException [^3]: 用反射的方式获取父类中的所有属性方法 [^4]: java 注解annotation的使用以及反射如何获取注解
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值