gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-02 09:05:45 24 4
gpt4 key购买 nike

我想转换对象的每个 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 有其他数据结构(如列表或映射),就会出现问题。例如,如果 PrintObject 类中有另一个字段:

private List<String> field5;

那么这段代码执行将会抛出 StackOverflowError。

List<String> list = new ArrayList<>();
list.add("test");

NestedObject nestedObject = NestedObject
.builder()
.field1("test")
.field2("test2")
.field3(1)
.build();

PrintObject printObject = PrintObject
.builder()
.field1("test")
.field2("Test")
.field3("test")
.field4(nestedObject)
.field5(list)
.build();

Utils.reflect(printObject);

关于如何使其与这些结构一起工作有什么想法吗?提前致谢。

field5 也可以是例如:

 Map<String,String>

甚至

 List<List<String>>

最佳答案

ArrayList 包含一个 long serialVersionUID 字段来帮助序列化。当您获取该值时,它会返回一个装箱的Long。对 Long 调用 getDeclaredFields 会返回一个包含字段 Long.MIN_VALUE 的数组,该字段是一个 Long。这就是无限循环的由来。

为了解决这个问题,我会为 Long 添加特殊情况处理,就像为 Integer 所做的那样。您还应该考虑所有其他装箱基元,例如 FloatByte

集合将由引用彼此链接的结构LinkedList或数组支持。对于链接结构,代码将遍历它们。为了支持数组支持的收集,您需要确定哪些字段是数组并迭代它们。

字段的类型,可以通过Field.getType获得。数组可以通过 Class.isArray 来识别。不同类型的数组有不同的类型,它们不像Java泛型那样是非具体化的。非原始值数组可以转换为 Object[],这在本例中很有用,但它是 not type safe 。获取数组中对象的类型Class.getComponentType可以使用。

需要像下面这样的东西来递归数组的条目。

final Class<?> fieldType = field.getType();
if (fieldType.isArray() && !fieldType.getComponentType().isPrimitive()) {
Object[] fs = (Object[]) f;
for (Object fi : fs) {
reflect(fi);
}
}

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

关于Java - 使用反射递归修改对象值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54856701/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com