将列表值反映到另一个列表中?
List listA; List listB;
我可以使用reflection将listA反映到listB中吗? 我得到了下面的代码但只反映了一个对象
public static B convert(A instance, Class targetClass) throws Exception { B target = (B)targetClass.newInstance(); for (Field targetField : targetClass.getDeclaredFields()) { targetField.setAccessible(true); Field field = instance.getClass().getDeclaredField(targetField.getName()); field.setAccessible(true); targetField.set(target, field.get(instance)); } return target; }
通常, convert
方法不太可能(对于List
或任何其他类型)。
调用Field.setAccessible(true)
允许对私有字段进行读写访问,但不允许通过Field.set()
修改final
字段( IllegalAccessException: Field is final
是抛出的IllegalAccessException: Field is final
exception)。
根据List
的实现,您尝试复制它可能会阻止它正常工作。 例如,使用ArrayList
例如:
// Note that this is an unchecked cast List listB = (List ) convert(listA, ArrayList.class);
尝试复制serialVersionUID
时失败。
对于ArrayList
static final serialVersionUID
,对已发布代码的以下更改将解决此问题:
public static B convert(A instance, Class targetClass) throws Exception { B target = (B)targetClass.newInstance(); for (Field targetField : targetClass.getDeclaredFields()) { targetField.setAccessible(true); Field field = instance.getClass().getDeclaredField(targetField.getName()); field.setAccessible(true); // Ignore attempts to set final fields try { targetField.set(target, field.get(instance)); } catch (IllegalAccessException e) { continue; } } return target; }
但是,下一个问题是convert
方法正在执行浅拷贝。 对于不同类型的List
,这个改变版本的convert
可能看起来工作正常但它不会将列表中的ClassA
对象转换为ClassB
(上面未经检查的强制转换隐藏了这个)。 这可能会导致稍后在应用程序中抛出ClassCastException
。
修复此问题可以通过添加另一个方法来包装convert
来实现:
public static , C> B convertList( List list, Class targetListClass, Class targetClass) throws Exception { B targetList = targetListClass.newInstance(); for (A object : list) { targetList.add(convert(object, targetClass)); } return targetList; }
然后需要将其称为:
List listB = (List ) convertList( listA, ArrayList.class, ClassB.class);
试试吧。
但它不是必需的。 您只需将第一个列表的内容添加到第二个列表:
List list2 = new ArrayList(list1);
看起来,你的两个List
声明了不同的generics类型。 所以你将不得不使用不安全的演员阵容。 但这样做感觉非常糟糕。 你究竟想要实现什么目标? 如果列表中的对象类型应该不同,那么为什么要尝试复制它们呢?
技术上说,是的,但仅限于某些条件。 假设您要将ClassA实例转换为ClassB实例。 开始转换的代码行如下:
ClassB bInstance = convert(aInstance, ClassB.class);
到目前为止我是否正确?
上面的代码将(1)创建一个新的ClassB对象,使用它的默认构造函数,(2)获取在ClassB上声明的所有字段(但没有来自任何ClassB超类型的字段!),(3)从ClassA和(4)获取相同的字段)将值从aInstance设置为新创建的ClassB实例中的字段。
到现在为止还挺好。
但是这只有当且仅当ClassA与ClassB具有完全相同的字段时才会起作用(它可能有更多字段)。 这是限制。 如果ClassA和ClassB不满足此前提条件,则必须分别捕获exception并处理这些情况,例如:
try { Field field = instance.getClass().getDeclaredField(targetField.getName()); field.setAccessible(true); try { targetField.set(target, field.get(instance)); } catch (IllegalArgumentException e) { handleIncompatibleType(target, targetField, field.get(instance)); } } catch (NoSuchFieldException e) { handleMissingFieldInA(instance, targetField); }
相同字段表示:相同的字段名称和相同的字段类型(或至少是“可转换”类型)
因此,如果您有List
但需要List
,则可以遍历第一个列表,将List项转换为ClassB对象并将它们写入目标列表。