You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何改进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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 02:07:35