Java运行时泛型信息使用

概述

由于Java泛型擦除机制,运行时无法获取本类的泛型信息,但父类或实现的接口的泛型类型信息会记录到类签名信息中。因此,假如我们需要在运行时获取本类的泛型信息,可以通过在创建本类对象的时候创建本类的匿名内部类的子类对象的方法实现。

创建匿名内部类的子类对象

创建对象时后面加上{}

List<String> list = new ArrayList<>() {};

获取父类或接口的泛型信息

Type接口是类型信息相关类的统一接口,带泛型类型的实现类为ParameterizedType,不带泛型的实现类为Class

获取父类的泛型信息

private Type getParameterizedType(int index) {  
    Type genericSuperclass = getClass().getGenericSuperclass();  
    if (genericSuperclass instanceof ParameterizedType) {  
        ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;  
        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();  
        if (actualTypeArguments.length > index) {  
            return actualTypeArguments[index];  
        }  
    }  
    return null;  
}

获取接口的泛型信息

private Type getParameterizedType(int index) {  
    Type[] genericInterfaces = getClass().getGenericInterfaces();  
    if (genericInterfaces.length > 0) {
        Type genericInterface = genericInterfaces[0];
        if (genericInterface instanceof ParameterizedType) {  
            ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;  
            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();  
            if (actualTypeArguments.length > index) {  
                return actualTypeArguments[index];  
            }  
        }  
    }
    return null;  
}

传递泛型类型

运行时传递带泛型类型,例如List<String>,无法直接使用Class对象来直接传递。通常使用TypeReference机制,Spring、Gson、Jackson等框架都有实现。

例如Jackson实现的TypeReference,反序列化时传递带泛型的类型

Map<String, List<BindDeviceReceiver>> data = objectMapper.convertValue(receiver.getData(), new TypeReference<Map<String, List<BindDeviceReceiver>>>() {});

又如Spring实现的ParameterizedTypeReference,获取带泛型信息的Type对象

Type type = new ParameterizedTypeReference<List<String>>() {}.getType();