如何获取泛型中T的具体类型

2022/03/22 Spring Java 共 2131 字,约 7 分钟

前言

平时业务中,有时候要做多态,用到泛型,又要反序列化,或者其他需要,在公共部分中,要知道当前泛型在具体子类实现的类,该如何做呢?

比如,抽象类AbstractHandler<T>想要知道StringHandler<String>中的String,T.class是行不通的,java的泛型是类型擦除,只知道泛型的上界。

要获得具体的泛型的class,可以通过继承关系中残留的信息来获取,具体来说,通过读取Class文件中的签名信息。

当然,还有一些其他的方法,比如如果有具体的对象,取出来反射一下可以获得,亦或者将class作为参数直接传进来,这都是可以的,但不够简洁。

实践

Spring自带工具

public interface IService<T> {
    default Class<T> getClazz() {
        return (Class<T>) GenericTypeResolver.resolveTypeArgument(getClass(), IService.class);
    }
}

自己的接口继承此接口即可,在实现自己接口的子类中就可以调用。

如果子类没有具体的类型会返回null,支持多继承,会一直向父类查找,直到找到将泛型实现为具体的类。

反射

public abstract class AbstractHandler<T> implements HandlerInterface<T> {
	public void test() {
		……
    	Class entityClass = (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
		……

	}
}

抽象类的子类通过抽象类的方法获取泛型类型。

getClass()获取当前类,getGenericSuperclass()获取当前类带泛型的父类,getActualTypeArguments()获取具体的泛型参数数组。

不支持多重继承。

其他可参考的实现

com.alibaba.fastjson.TypeReference

package com.alibaba.fastjson;

import com.alibaba.fastjson.util.ParameterizedTypeImpl;
import com.alibaba.fastjson.util.TypeUtils;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

public class TypeReference<T> {
    static ConcurrentMap<Type, Type> classTypeCache = new ConcurrentHashMap(16, 0.75F, 1);
    protected final Type type;
    public static final Type LIST_STRING = (new TypeReference<List<String>>() {
    }).getType();

    protected TypeReference() {
        Type superClass = this.getClass().getGenericSuperclass();
        Type type = ((ParameterizedType)superClass).getActualTypeArguments()[0];
        Type cachedType = (Type)classTypeCache.get(type);
        if (cachedType == null) {
            classTypeCache.putIfAbsent(type, type);
            cachedType = (Type)classTypeCache.get(type);
        }

        this.type = cachedType;
    }


    public Type getType() {
        return this.type;
    }
}

带泛型的类在使用fastjson反序列化的时候需要我们传一个匿名TypeReference子类,就是通过父类一系列反射的操作获得具体类的, Type superClass = this.getClass().getGenericSuperclass(); Type type = ((ParameterizedType)superClass).getActualTypeArguments()[0];

与我们之前自己进行的操作类似,只不过还将类型放入了ConcurrentHashMap中做了缓存以供后续使用。

文档信息

Search

    Table of Contents