【问题标题】:Library to print all public fields of nested Java objects?打印嵌套Java对象的所有公共字段的库?
【发布时间】:2012-02-27 13:17:11
【问题描述】:

我需要打印嵌套 Java 对象的所有公共字段。这些对象只包含数据,没有方法。在任何级别的对象树(叶节点除外)上,字段可能是 Maps、Lists、Sets 和数组。叶节点是原始类型。 嵌套字段应打印为以下格式的字符串:

<fieldName1>.<fieldName2>. ... <fieldNameN>==<value>

地点:

<fieldName1> -- root (top level) field name
<fieldNameN> -- N-level field name
<value> -- N-level field value.

有没有图书馆可以解决这个问题?

【问题讨论】:

    标签: java reflection introspection


    【解决方案1】:

    以下示例远未完成 - 它草拟了一个解决方案并显示了一些缺陷:

    public class Main {
        private static Set<Object> visited = new HashSet<Object>();
        public String s = "abc";
        public int i = 10;
        public Main INSTANCE = this;
    
    public static void main (String[] args) throws Exception
    {
       printFields(new Main(), "");
    }
    
        private static void printFields(Object obj, String pre) throws Exception{
          Field[] fields = obj.getClass().getFields();
          for (Field field:fields) {
             String value = "";
             String type = field.getType().toString();
    
             // handle primitve values
             if (type.equals("int")) {
               value += field.getInt(obj);
             } 
    
             // handle special types, you may add Wrapper classes
              else if (type.equals("class java.lang.String")) {
               value = field.get(obj).toString();  
             } 
    
             // handle all object that you want to inspect
              else {
               if (visited.contains(field.get(obj))) {
                 // necessary to prevent stack overflow
                 value = "CYCLE DETECTED";
               } else {
                 // recursing deeper
                 visited.add(field.get(obj));
                 pre += field.getName() + ".";
                 printFields(field.get(obj), pre);
               }
             }     
    
             System.out.printf("%s%s = %s%n", pre, field.getName(), value);
          }
        }
    }
    
    • 我们在反射 API 中找到所需的一切
    • 我们需要递归遍历对象树
    • 我们需要对原语进行一些特殊处理
    • 我们希望对不可变类型进行一些特殊处理(例如,我们不想递归到 String 对象中
    • 如果我们两次访问一个对象,我们需要小心。

    注意 - 代码很丑,希望它足以给你一个想法

    【讨论】:

    • 然而,我的子问题仍然存在:我需要明确区分 Map 和 Iterable 来迭代这些集合 - 另一个特殊情况。如何找出该类实现了特定接口,例如 Map 或 Iterable?
    • 我跳过了那个,因为:查看集合不符合您的格式要求。您可以使用get(0)get(1) 作弊以获得列表,但您在集合中输了(我们无法从集合中获取单个值)
    • 但是无论如何,一旦你决定如何格式化输出 with 集合,你可以将集合类型的“处理程序”插入到 if/else 链中.比如,如果你看到一个数组或列表,然后从数组/集合中获取所有对象,并使用相同的 printFields 方法一一检查它们。
    • 打印地图成员可以这样完成:&lt;fieldMapName&gt;.&lt;fieldKeyName&gt;.&lt;fieldOtherName&gt;...,对于列表和数组:&lt;fieldListName&gt;.&lt;fieldListElementName&gt;.&lt;fieldOtherName&gt;... 其中 是“伪字段”
    【解决方案2】:

    不需要库。这在java中称为反射。看看Class documentation 使用这个你可以做到:

    for(Field field : YourClass.class.getFields()){
        //Print field info
    }
    

    编辑: 你可以通过getDeclaringClass() 获得Field 的类。可以通过isPrimitive() 来检查这个类是否是一个原语。如果是,您可以打印该值。如果没有,您可以递归并打印该字段的字段。

    【讨论】:

    • 谢谢,是的,这是查找类字段的好方法。然而,我还需要找到一个叶字段值。所以问题是——你有一个对象,一个嵌套在 N 层的对象的字段名——如何找到这个嵌套很深的字段值?
    • 如果嵌套字段是 Map、数组或 Iterable 怎么办?然后,您需要向下迭代到这些集合包含的所有对象。如您所见,要解决此任务还需要做更多工作......
    • @dokondr 我已经添加了更多关于此的信息,所有这些信息都可以从我链接到的文档中获得。
    • @jim 我明白了,谢谢。然而,我需要明确区分 Map 和 Iterable 来迭代这些集合——另一种特殊情况。如何找出该类实现了特定接口,例如 Map 或 Iterable?
    猜你喜欢
    • 2021-05-06
    • 2022-11-25
    • 2020-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-19
    • 1970-01-01
    相关资源
    最近更新 更多