关联Java字段类型和泛型参数
考虑以下类别:关联Java字段类型和泛型参数,java,generics,reflection,Java,Generics,Reflection,考虑以下类别: class A { B<Integer> b; } class B<T> { T t; } 这样,当调用create(A.class)时,返回的值是A的实例,其中包含b.t中的整数。当然,除了类之外,方法不能有任何关于A的知识 众所周知,如何找出A中b的类型是b 我正在寻找一种方法,以确定B中的t字段打算具有B的第一个类型参数的类型。作为类型参数的字段类型可分配给java.lang.reflect.TypeVariable。换句话说,f
class A {
B<Integer> b;
}
class B<T> {
T t;
}
这样,当调用create(A.class)
时,返回的值是A的实例,其中包含b.t
中的整数。当然,除了类之外,方法不能有任何关于A
的知识
众所周知,如何找出A
中b
的类型是b
我正在寻找一种方法,以确定
B
中的t
字段打算具有B
的第一个类型参数的类型。作为类型参数的字段类型可分配给java.lang.reflect.TypeVariable
。换句话说,field.getGenericType()
在为字段B.t
调用时返回TypeVariable
的实例
下面的完整示例适用于问题中给出的玩具箱。一般情况更为复杂,因为必须跟踪多个级别的类型参数
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
class Main {
static class A {
B<Integer> b;
}
static class B<T> {
T t;
}
public static void main(String[] args) throws Exception {
A a = (A)create(A.class);
System.out.println(a.b.t.getClass());
// prints java.lang.Integer
}
static Object create(Class<?> clazz) throws Exception {
return create(clazz, new Type[0]);
}
static Object create(Class<?> clazz, Type[] typeArguments) throws Exception {
Object object;
if (clazz == Integer.class || clazz == int.class) {
return 0;
} else {
object = clazz.newInstance();
}
for (Field field : object.getClass().getDeclaredFields()) {
Type[] fieldTypeArguments = { };
Type fieldType = field.getGenericType();
if (fieldType instanceof TypeVariable) {
TypeVariable<?> typeVariable = (TypeVariable<?>) fieldType;
TypeVariable<?>[] typeParameters = typeVariable.getGenericDeclaration().getTypeParameters();
for (int i = 0; i < typeParameters.length; i++) {
if (typeParameters[i] == typeVariable) {
fieldType = typeArguments[i];
}
}
} else if (fieldType instanceof ParameterizedType) {
fieldTypeArguments = ((ParameterizedType) fieldType).getActualTypeArguments();
}
Class<?> fieldClass = null;
if (fieldType instanceof Class) {
fieldClass = (Class<?>) fieldType;
} else if (fieldType instanceof ParameterizedType) {
fieldClass = (Class<?>) ((ParameterizedType) fieldType).getRawType();
}
field.set(object, create(fieldClass, fieldTypeArguments));
}
return object;
}
}
import java.lang.reflect.Field;
导入java.lang.reflect.ParameterizedType;
导入java.lang.reflect.Type;
导入java.lang.reflect.TypeVariable;
班长{
静态A类{
B B;
}
静态B类{
T;
}
公共静态void main(字符串[]args)引发异常{
A=(A)创建(A.class);
System.out.println(a.b.t.getClass());
//打印java.lang.Integer
}
静态对象创建(类clazz)引发异常{
返回创建(clazz,新类型[0]);
}
静态对象创建(类clazz,类型[]typeArguments)引发异常{
对象对象;
if(clazz==Integer.class | | clazz==int.class){
返回0;
}否则{
object=clazz.newInstance();
}
对于(字段:object.getClass().getDeclaredFields()){
类型[]fieldTypeArguments={};
Type fieldType=field.getGenericType();
if(fieldType instanceof TypeVariable){
类型变量类型变量=(类型变量)字段类型;
TypeVariable[]typeParameters=TypeVariable.getGenericDeclaration().getTypeParameters();
对于(int i=0;i
由于类型擦除,无法查看字段的类型。您所能做的最好的事情就是检查当前值的类型Class bClass=/*whatever*/;如果(bClass.isInstance(t)){…}
Java没有删除所有泛型类型信息。很容易发现A
中B
的类型参数是Integer
。因此,某些泛型类型信息必须存储在类文件中。我的问题是,是否可以使用此信息将类型参数与B
和B.t
的字段类型关联起来。Michael是正确的。但是,您还需要了解泛型用于增强编译时类型检查。它不能应用于从类对象创建对象,除了已经存在的对象(即类中的T newInstance()
)@MuhKarma它不会删除所有类型信息,但在特定情况下会删除。“因此必须存储一些泛型类型信息”是的,完全正确。一些它在第一种情况下会这样做,而不是在第二种情况下。这种行为是定义良好的,以前在堆栈溢出和其他地方都已经讨论过很多次。只需谷歌“Java类型擦除”
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
class Main {
static class A {
B<Integer> b;
}
static class B<T> {
T t;
}
public static void main(String[] args) throws Exception {
A a = (A)create(A.class);
System.out.println(a.b.t.getClass());
// prints java.lang.Integer
}
static Object create(Class<?> clazz) throws Exception {
return create(clazz, new Type[0]);
}
static Object create(Class<?> clazz, Type[] typeArguments) throws Exception {
Object object;
if (clazz == Integer.class || clazz == int.class) {
return 0;
} else {
object = clazz.newInstance();
}
for (Field field : object.getClass().getDeclaredFields()) {
Type[] fieldTypeArguments = { };
Type fieldType = field.getGenericType();
if (fieldType instanceof TypeVariable) {
TypeVariable<?> typeVariable = (TypeVariable<?>) fieldType;
TypeVariable<?>[] typeParameters = typeVariable.getGenericDeclaration().getTypeParameters();
for (int i = 0; i < typeParameters.length; i++) {
if (typeParameters[i] == typeVariable) {
fieldType = typeArguments[i];
}
}
} else if (fieldType instanceof ParameterizedType) {
fieldTypeArguments = ((ParameterizedType) fieldType).getActualTypeArguments();
}
Class<?> fieldClass = null;
if (fieldType instanceof Class) {
fieldClass = (Class<?>) fieldType;
} else if (fieldType instanceof ParameterizedType) {
fieldClass = (Class<?>) ((ParameterizedType) fieldType).getRawType();
}
field.set(object, create(fieldClass, fieldTypeArguments));
}
return object;
}
}