Reputation: 131
How To Instantiate a java.util.ArrayList with Generic Class Using Reflection? I am writing a method that sets java.util.List on target object. A target object and a generic type of list is knowing in runtime:
public static void initializeList(Object targetObject, PropertyDescriptor prop, String gtype) {
try {
Class clazz = Class.forName("java.util.ArrayList<"+gtype+">");
Object newInstance = clazz.newInstance();
prop.getWriteMethod().invoke(targetObject, newInstance);
} catch (Exception e) {
e.printStackTrace();
}
}
Upvotes: 13
Views: 27731
Reputation: 1
This can init a Object contains List successfully.
package com.y24.init;
import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import lombok.SneakyThrows;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
public class ObjInit {
@SneakyThrows
public static void main(String[] args) {
Object o = objInit(Persons.class);
}
@SneakyThrows
public static Object objInit(Class<?> clazz) {
//基础数据类型
if (clazz == int.class || clazz == Integer.class) {
Object defaultValue = 1;
return defaultValue;
} else if (clazz == long.class || clazz == Long.class) {
Object defaultValue = 1L;
return defaultValue;
} else if (clazz == double.class || clazz == Double.class) {
Object defaultValue = 3.14;
return defaultValue;
} else if (clazz == boolean.class || clazz == Boolean.class) {
Object defaultValue = false;
return defaultValue;
} else if (clazz == String.class) {
Object defaultValue = "Hello world!";
return defaultValue;
}
Object obj = null;
try {
obj = clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
// 首先得到pojo所定义的字段
Field[] fields = clazz.getDeclaredFields();
for (Field curField : fields) {
// 设置字段可访问(必须,否则报错)
curField.setAccessible(true);
Class<?> curFieldType = curField.getType();
// 集合List元素
if (curFieldType.equals(List.class)) {
// 当前集合的泛型类型
Type genericType = curField.getGenericType();
if (genericType instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) genericType;
// 得到泛型里的class类型对象
Class<?> actualTypeArgument = (Class<?>) pt.getActualTypeArguments()[0];
List<Object> curEleList = new ArrayList<>();
//Object actualType = actualTypeArgument.newInstance();
//....actualType字段处理
Object actualType = objInit(actualTypeArgument);
curEleList.add(actualType);
curField.set(obj, curEleList);
}
} else {
curField.set(obj, objInit(curFieldType));
}
}
System.out.println(JSONObject.toJSONString(obj));
return obj;
}
}
@Data
class Persons {
private int count;
private List<Person> persons;
}
@Data
class Person {
private String name;
private int age;
private Address address;
private List<String> names;
}
@Data
class Address {
private String city;
private String zipCode;
// getters and setters...
}
Upvotes: 0
Reputation: 4748
There's no need to do any reflection for creating your List. Just pass in some additional type information (usually done by passing a class of the correct type).
public static <T> List<T> createListOfType(Class<T> type) {
return new ArrayList<T>();
}
Now you have a list of the required type you can presumably/hopefully set it directly on your targetObject
without any reflection.
Upvotes: 7
Reputation: 533700
Generics is largely a compile time feature. What you are trying to do is the same as
public static void initializeList(Object targetObject, PropertyDescriptor prop, String gtype) {
prop.getWriteMethod().invoke(targetObject, new ArrayList());
}
Note: This could change with Types in Java 7.
Upvotes: 0
Reputation: 1
An object doesn't know about its generic type at execution time. Just create a new instance of the raw type (java.util.ArrayList). The target object won't know the difference (because there isn't any difference).
Upvotes: 0
Reputation: 49794
Generics only work at compile time, therefore if you're using reflection, they won't be available.
See more about this here.
Upvotes: 0
Reputation: 103827
Generics are a compile-time only "trick".
Reflection is runtime-only.
Basically, you can't - you can only create a "raw" ArrayList
. If you need to pass it into methods that take generic parameters, casting it directly after construction will be safe (regardless of the "unchecked" warning). In this example, there's no compile-time type safety anyway due to using general Objects
, so no casting is needed.
Upvotes: 2
Reputation: 1502406
An object doesn't know about its generic type at execution time. Just create a new instance of the raw type (java.util.ArrayList
). The target object won't know the difference (because there isn't any difference).
Basically Java generics is a compile-time trick, with metadata in the compiled classes but just casting at execution time. See the Java generics FAQ for more information.
Upvotes: 15