如何改进Java方法获取MyDocument子类实例的所有已赋值有效属性
如何改进MyDocument类的getProperties方法以返回正确的属性HashMap
我定义了一个代表文档的MyDocument类,包含通用属性和子类(Contract、Summary)的特定属性,属性分为必填和可选两类,部分属性可能未赋值。目标是生成一个HashMap,仅包含实例的所有已赋值属性(包括父类与子类属性)。
当前实现的getProperties方法仅返回子类属性,还会包含内部类的外部实例引用(this$0),且未包含父类的已赋值属性,输出结果不符合预期。请问如何改进该方法,使其接收MyDocument子类实例时,返回符合要求的HashMap?
MyDocument类代码
import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map.Entry; import it.smi.json.JSONArray; import it.smi.json.JSONObject; public class MyDocument { String documentClass; // 必填 String name; // 必填 String notes; // 可选 public class Contract extends MyDocument { String providerCode; // 必填 String providerName; // 必填 long activationDate; // 必填 long expirationDate; // 必填 String expirationNotifyUser; // 可选 String expirationNotifyUserType; // 可选 Contract (String name, String notes, long activationDate, long expirationDate) { this.documentClass = "contract"; // 常量 this.name = name; this.notes = notes; this.providerCode = null; this.providerName = null; this.activationDate = activationDate; this.expirationDate = expirationDate; this.expirationNotifyUser = null; this.expirationNotifyUserType = null; } // 构造方法 } public class Summary extends MyDocument { String origin; // 必填 String providerCode; // 可选 String providerName; // 可选 Summary (String name, String notes) { this.documentClass = "summary"; this.origin = "area"; // 常量 this.name = name; this.notes = notes; this.providerCode = null; this.providerName = null; } // 构造方法 } public HashMap<String, Object> getProperties () throws Exception { HashMap<String, Object> toReturn = new HashMap<String, Object>(); Field[] fields = this.getClass().getDeclaredFields(); for(Field f : fields) if (f.get(this) != null) toReturn.put(f.getName(), f.get(this)); // 我试过添加 !f.getName().contains("this$") && 到判断条件里,本地运行有效,但不确定部署到服务器后是否还能正常工作,所以不太想用这种方式 return toReturn; } // getProperties }
测试代码与输出对比
public static void main(String args[]) throws Exception { Summary summ = new MyDocument().new Summary("SumName", "SumNotes"); Contract cont = new MyDocument().new Contract("ContName", "ContNotes", 12345, 67890); System.out.println("### Summary:\n" + summ.getProperties()); System.out.println("### Contract:\n" + cont.getProperties()); /* * 当前输出: * ### Summary: {origin=area, this$0=myName.test.generic.MyDocument@6d06d69c} ### Contract: {this$0=myName.test.generic.MyDocument@4e25154f, activationDate=12345, expirationDate=67890} * 期望输出: * ### Summary: {documentClass=summary, name=SumName, notes=SumNotes, origin=area} ### Contract: {documentClass=contract, name=ContName, notes=ContNotes, activationDate=12345, expirationDate=67890} */ }
改进方案
要实现需求,需要解决三个核心问题:遍历父类字段、过滤合成字段、区分基本类型与引用类型的非空判断。改进后的getProperties方法如下:
public HashMap<String, Object> getProperties() throws Exception { HashMap<String, Object> toReturn = new HashMap<>(); Class<?> currentClass = this.getClass(); // 遍历当前类及其所有父类,直到Object类 while (currentClass != Object.class) { Field[] fields = currentClass.getDeclaredFields(); for (Field f : fields) { // 跳过编译器自动生成的合成字段(如内部类的this$0) if (f.isSynthetic()) { continue; } // 设置可访问私有字段,兼容后续字段权限修改 f.setAccessible(true); Object value = f.get(this); // 处理字段值:引用类型非null才添加,基本类型直接保留(因必填基本类型已赋值有效数值) if (f.getType().isPrimitive()) { toReturn.put(f.getName(), value); } else { if (value != null) { toReturn.put(f.getName(), value); } } } // 切换到父类继续遍历 currentClass = currentClass.getSuperclass(); } return toReturn; }
关键改进点说明
- 遍历父类字段:通过循环调用
getSuperclass(),从子类向上遍历到Object类,确保父类MyDocument的已赋值属性被纳入结果 - 可靠过滤合成字段:使用
f.isSynthetic()判断编译器自动生成的字段,比字段名匹配更稳定,避免跨环境兼容性问题 - 区分类型处理:针对基本类型(如
long)直接保留值(因构造方法已为必填基本类型赋值有效数值),引用类型仅保留非null值 - 兼容私有字段:调用
setAccessible(true),确保即使后续字段改为私有,仍能正常获取值
内容的提问来源于stack exchange,提问作者Fra
相关产品推荐
相关产品推荐

