为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

慕容森 2022-07-06 10:03:42
我想转换 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@Builderpublic class PrintObject {    private String field1;    private String field2;    private String field3;    private NestedObject field4;}@Data@Builderpublic 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;
查看完整描述

1 回答

?
慕慕森

TA贡献1856条经验 获得超17个赞

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()) {

    Object[] fs = (Object[]) f;

    for (Object fi : fs) {

        reflect(fi);

    }

}

另一个问题是可能导致进一步的循环引用StackOverflowException。如果将一个列表作为其自身的成员添加,它将无限递归。有必要跟踪以前访问过的对象,而不是两次访问它们。理想情况下,这将使用 an IdentityHashMap,因为您关心对象的实例而不是它们的相等性。


查看完整回答
反对 回复 2022-07-06
  • 1 回答
  • 0 关注
  • 258 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信