前置条件:最近在写框架工具,现拿到了一个类的class,遍历他的属性时,遇到Collection的子接口问题时,无法确定类中的属性是一个List还是set 或者Queue ,只能确定属性是Collection的子接口。但是需要遍历这个属性的同时,假如他是集合类,则需要调用其add方法,所以需要拿到这个属性的实例子类。
需求例子:比如我通过反射获得了一个类的属性:
private List<String> list
有了list的字节码class,现在需要创建他的某个子类实例对象并且调用其中的方法。
因为是list是接口,所以不能通过class创建其实例
此贴终结, 方案: 取class分类讨论。
//属性
Object instance = tempC.newInstance();
//迭代解析
resoleParam(instance,instance.getClass());
Collection collection = null;
//如果是list 这样的接口或抽象类
if(aClass.isInterface()|| Modifier.isAbstract(aClass.getModifiers())){
//实例化它的可用类
collection = getNewInstanceWhenCollection(aClass);
}else{
//如果是可实例子类,则直接调用
collection = (Collection)aClass.newInstance();
}
collection.add(instance);
field.set(obj,collection);
/**
* 当class为collection 子接口或抽象类时,分类讨论 取出适合class的子类实例
* @param clazz
* @return
*/
private Collection getNewInstanceWhenCollection(Class clazz){
//判断是否是集合
if(!Collection.class.isAssignableFrom(clazz)){
return null;
}
//判断是list分支吗
if(List.class.isAssignableFrom(clazz)){
return new ArrayList();
}
//判断是set分支吗
if(Set.class.isAssignableFrom(clazz)){
return new HashSet();
}
//判断是队列分支吗
if(Queue.class.isAssignableFrom(clazz)){
return new LinkedList();
}
return null;
}
都使用反射了,那创建实例就是你说了算,List的子类你任意创建一个,再赋值给list属性就行了。
直接 set 实现类即可,示例代码如下:
public class Test {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
Bean bean = new Bean();
Class<? extends Bean> cls = bean.getClass();
Field list = cls.getDeclaredField("list");
if (Collection.class.isAssignableFrom(list.getType())) {
list.setAccessible(true);
list.set(bean, new ArrayList<>());
}
}
}
T obj = beanClass.newInstance();
Class<?> oo = obj.getClass();
List<Class<?>> clazzs = new ArrayList<>();
while (true) {
clazzs.add(oo);
oo = oo.getSuperclass();
if (oo == null || oo == Object.class) {
break;
}
}