List <ClassA> listA; List <ClassB> listB;
我可以使用反射将listA反映到listB中吗?我得到了下面的代码但只反映了一个对象
public static <A, B> B convert(A instance,
Class<B> 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;
}
答案 0 :(得分:3)
一般情况下,convert
方法不太适用(适用于List
或任何其他类型)。
调用Field.setAccessible(true)
允许对私有字段进行读写访问,但不允许通过final
修改Field.set()
字段(抛出IllegalAccessException: Field is final
异常)。
根据您尝试复制的List
的实施情况,可能会阻止其正常运行。例如,使用ArrayList
,例如:
// Note that this is an unchecked cast
List<ClassB> listB = (List<ClassB>) convert(listA, ArrayList.class);
尝试复制serialVersionUID
时失败。
以下对已发布代码的更改解决了static final serialVersionUID
中ArrayList
的此问题:
public static <A, B> B convert(A instance,
Class<B> 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 <A, B extends List<C>, C> B convertList(
List<A> list, Class<B> targetListClass, Class<C> targetClass)
throws Exception {
B targetList = targetListClass.newInstance();
for (A object : list) {
targetList.add(convert(object, targetClass));
}
return targetList;
}
然后需要将其称为:
List<ClassB> listB = (List<ClassB>) convertList(
listA, ArrayList.class, ClassB.class);
答案 1 :(得分:1)
试试吧。
但不需要它。您只需将第一个列表的内容添加到第二个列表中即可:
List list2 = new ArrayList(list1);
看起来,你的两个List
声明了不同的泛型类型。所以你将不得不使用不安全的演员阵容。但这样做感觉非常糟糕。你究竟想要实现什么目标?如果列表中的对象类型应该不同,那么为什么要尝试复制它们呢?
答案 2 :(得分:0)
技术上说,是的,但仅限于某些条件。假设您要将ClassA实例转换为ClassB实例。开始转换的代码行如下:
ClassB bInstance = convert(aInstance, ClassB.class);
到目前为止我是否正确?
上面的代码将(1)创建一个新的ClassB对象,使用它的默认构造函数,(2)获取在ClassB上声明的所有字段(但没有字段来自任何ClassB超类型!),(3) )从ClassA获取相同的字段,(4)将值从aInstance设置为新创建的ClassB实例中的字段。
到目前为止一切顺利。
但这只有当且仅当ClassA与ClassB具有完全相同的字段时才会起作用(它可能有更多字段)。这是限制。如果ClassA和ClassB不满足此前提条件,则必须分别捕获异常并单独处理这些情况,例如:
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<ClassA>
但需要List<ClassB>
,则可以遍历第一个列表,将List项目转换为ClassB对象并将它们写入目标列表。