杰瑞科技汇

Java如何获取泛型的Class对象?

在Java中获取泛型的Class对象

在Java中获取泛型的Class对象是一个常见但有些棘手的问题,因为Java的泛型在运行时会被擦除(type erasure),以下是几种获取泛型Class对象的方法:

Java如何获取泛型的Class对象?-图1
(图片来源网络,侵删)

使用Class.getGenericSuperclass()

这是最常用的方法,可以获取父类的泛型信息:

public class MyClass<T> {
    public Class<T> getGenericClass() {
        ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();
        return (Class<T>) genericSuperclass.getActualTypeArguments()[0];
    }
}

使用示例:

public class StringMyClass extends MyClass<String> {
    public static void main(String[] args) {
        StringMyClass instance = new StringMyClass();
        Class<String> stringClass = instance.getGenericClass();
        System.out.println(stringClass); // 输出: class java.lang.String
    }
}

使用Class.getGenericInterfaces()

如果类实现了泛型接口,可以使用此方法:

public class MyClass implements MyInterface<String> {
    public Class<String> getGenericClass() {
        ParameterizedType genericInterface = (ParameterizedType) getClass().getGenericInterfaces()[0];
        return (Class<String>) genericInterface.getActualTypeArguments()[0];
    }
}

通过反射获取字段/方法的泛型类型

可以获取字段或方法参数的泛型类型:

Java如何获取泛型的Class对象?-图2
(图片来源网络,侵删)
public class GenericFieldExample<T> {
    private T value;
    public Class<T> getValueType() throws NoSuchFieldException {
        Field field = GenericFieldExample.class.getDeclaredField("value");
        Type genericType = field.getGenericType();
        if (genericType instanceof ParameterizedType) {
            return (Class<T>) ((ParameterizedType) genericType).getActualTypeArguments()[0];
        }
        return null;
    }
}

使用TypeToken(Google Guava)

Guava库提供了更优雅的方式处理泛型类型:

import com.google.common.reflect.TypeToken;
public class TypeTokenExample<T> {
    private TypeToken<T> typeToken = new TypeToken<T>(getClass()) {};
    public Class<T> getGenericClass() {
        return typeToken.getRawType();
    }
}

使用示例:

public class StringExample extends TypeTokenExample<String> {
    public static void main(String[] args) {
        StringExample example = new StringExample();
        System.out.println(example.getGenericClass()); // 输出: class java.lang.String
    }
}

注意事项

  1. 泛型类型在运行时会被擦除,所以只能获取到编译时保留的信息
  2. 这些方法通常在子类中才能正确获取泛型参数
  3. 对于复杂的嵌套泛型,处理会更复杂
  4. 如果泛型参数是通配符(如),可能无法获取具体的类型

完整示例

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
public class GenericTypeExample<T> {
    public Class<T> getGenericType() {
        Type type = getClass().getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) type;
            Type[] typeArgs = parameterizedType.getActualTypeArguments();
            return (Class<T>) typeArgs[0];
        }
        return null;
    }
    public static void main(String[] args) {
        StringExample stringExample = new StringExample();
        System.out.println("String type: " + stringExample.getGenericType());
        IntegerExample integerExample = new IntegerExample();
        System.out.println("Integer type: " + integerExample.getGenericType());
    }
}
class StringExample extends GenericTypeExample<String> {}
class IntegerExample extends GenericTypeExample<Integer> {}

输出:

String type: class java.lang.String
Integer type: class java.lang.Integer

选择哪种方法取决于你的具体需求和项目环境,如果项目中已经使用了Guava,推荐使用TypeToken;否则,使用反射方法也是可行的。

分享:
扫描分享到社交APP
上一篇
下一篇