猿问

Java - 使用反射递归修改对象值

我想转换 Object 的每个 String 属性(以及它的嵌套对象),我正在使用以下递归方法通过反射 API 来实现:


    public static void reflect(Object obj) {

        if (obj == null) {

            return;

        }

        Class klazz = obj.getClass();

        if (klazz.isPrimitive()

                || obj instanceof Integer

                || obj instanceof Double

                || obj instanceof Boolean)

            return;

        else {

            try {

                for (Field field : klazz.getDeclaredFields()) {

                    field.setAccessible(true);

                    Object f = field.get(obj);

                    if(f instanceof String) {

                        f = transform(f);

                        field.set(obj, f);

                    }

                    else {

                        reflect(f);

                    }

                }

            } catch (IllegalAccessException e) {

                e.printStackTrace();

            } catch (IllegalArgumentException e) {

                e.printStackTrace();

            }

        }

    }


    private static Object transform(Object f) {

        f = f + "blabla";

        return f;

    }



@Data

@Builder

public class PrintObject {

    private String field1;

    private String field2;

    private String field3;

    private NestedObject field4;

}


@Data

@Builder

public class NestedObject {

    private String field1;

    private String field2;

    private Integer field3;

}


NestedObject nestedObject = NestedObject

                .builder()

                .field1("test")

                .field2("test2")

                .field3(1)

                .build();


PrintObject printObject = PrintObject

      .builder()

      .field1("test")

      .field2("Test")

      .field3("test")

      .field4(nestedObject)

      .build();


Utils.reflect(printObject);

到目前为止,一切正常,如果我执行此操作,那么所有字符串值最后都会附加“blabla”。如果 PrintObject 具有其他数据结构(如 List 或 Map),则会出现问题。例如,如果 PrintObject 类中有另一个字段:


private List<String> field5;


慕容森
浏览 260回答 1
1回答

慕慕森

ArrayList包含一个long serialVersionUID帮助序列化的字段。当您获得该值时,它会返回一个 boxed Long。调用getDeclaredFieldsonLong返回一个包含字段的数组,该字段Long.MIN_VALUE是Long. 这就是无限循环的来源。Long为了解决它,我会像你一样添加特殊情况处理Integer。您还应该考虑所有其他盒装原语,例如Float和Byte。集合将由引用彼此链接的结构LinkedList或数组支持。对于链接结构,代码将遍历它们。要支持数组支持的收集,您需要确定哪些字段是数组并遍历它们。字段的类型,通过Field.getType获得。数组可以通过Class.isArray来识别。不同类型的数组有不同的类型,它们不像 Java 泛型那样是非具体化的。可以将非原始值的数组强制转换Object[]为在这种情况下很有用,但它不是类型安全的。可以使用Class.getComponentType来获取数组中对象的类型。需要像下面这样的东西来递归数组的条目。final Class<?> fieldType = field.getType();if (fieldType.isArray() && !fieldType.getComponentType().isPrimitive()) {&nbsp; &nbsp; Object[] fs = (Object[]) f;&nbsp; &nbsp; for (Object fi : fs) {&nbsp; &nbsp; &nbsp; &nbsp; reflect(fi);&nbsp; &nbsp; }}另一个问题是可能导致进一步的循环引用StackOverflowException。如果将一个列表作为其自身的成员添加,它将无限递归。有必要跟踪以前访问过的对象,而不是两次访问它们。理想情况下,这将使用 an IdentityHashMap,因为您关心对象的实例而不是它们的相等性。
随时随地看视频慕课网APP

相关分类

Java
我要回答