Java如何获得泛型类中的泛型类型T.class

 更新时间:2024年12月14日 15:37:05   作者:nvd11  
获取泛型符号E的Class对象的方法,1.反射方案利用匿名子类实例化,但该方法有特殊限制,2.反射方案2直接指定泛型类型,但不灵活,3.构造方法方案在初始化时传入泛型类,但有写错风险

Java获得泛型类的泛型类型T.class

假如我们写了1个泛型类MyBase

public class MyBase<E> {
    public MyBase(){
        
    }

    public Class<?> getEClass() {
		?
    }   
}

我想写1个getEClass 的方法, 获取泛型符号E的Class对象。

直接用E.class E.getClass()都是不合法的, 因为E只是个符号, 没有被实例化。

1. 反射方案

各种google 各种Stackoverflow 后, 找到利用反射的1个方法。

public class MyBase<E> {
    public MyBase(){
        
    }

    public Class<?> getEClass() {
        
        //get the Class object of this own class 
        Class<? extends MyBase> thisClass = this.getClass();

        //get the Type Object of supper class
        Type superClassType = thisClass.getGenericSuperclass();
        ParameterizedType pt = (ParameterizedType)superClassType;

        //get the Generic Type array
        Type[] genTypeArr = pt.getActualTypeArguments();
        Type genType = genTypeArr[0];
        if (false == genType instanceof Class){
            return Object.class;
        }

        return (Class<Object>) genType;
    }
}

这个方法被测试过, 但是有个很特别的限制,

一定要实例化匿名子类才有效果。

例如:

   @Test
    void testMyBase() {
        MyBase<String> mybase = new MyBase<String>(){};
        log.info("E class is {}",mybase.getEClass());
    }

注意new MyBase(){} 后面的大括号, 意思不是实例化MyBase对象, 而是实例化MyBase的匿名子类。

如果我们写多1个具体的子类MyList

public class MyList<E> extends MyBase<E> {
    public MyList(){

	}
}

测试方法:

   @Test
    void testGetEClass() {
        MyList<String> mylist = new MyList<String>();
        log.info("E class is {}",mylist.getEClass());
    }

同样不行, 原因是

		//get the Type Object of supper class
        Type superClassType = thisClass.getGenericSuperclass();
        ParameterizedType pt = (ParameterizedType)superClassType;

这里 我们只能通过本类的Class对象去获得1个父类 ParameterizedType (包括泛型参数列表的Type)

而JDK本身只提供了getGenericSuperclass()方法去获得父类的Type 对象

但是没有提供例如getGenericClass() 去获取本类的Type对象…

所以一旦我们不实用匿名子类

当下面代码被执行时

MyList<String> mylist = new MyList<String>();
log.info("E class is {}",mylist.getEClass());

thisClass.getGenericSuperclass() 会获得MyList的父类MyBase的Type, 问题是MyBase没有被实例化, 所以pt.getActualTypeArguments()[0] 只会返回E

本身 就return null了

但是如果我们利用匿名子类的化

当下面代码被执行时

MyList<String> mylist = new MyList<String>(){};
log.info("E class is {}",mylist.getEClass());

mylist 的类实际上是1个匿名子类MyList$1, 它的父类就是MyList, 而匿名子类的父类在JVM实际上是被实例化的

所以pt.getActualTypeArguments()[0] 会返回泛型具体类String 的Class。

2. 反射方案2

匿名子类毕竟有点奇怪。

如果避免使用你匿名子类, 我们还有1个办法

public class MySet extends MyBase<String> {
    public MySet(){
  
    }
}

如上面这个MySet类, 它直接继承MyBase时指定了具体泛型, 令到自己本身不是1个泛型类。

这样的话, 不用匿名子类也一样可以获得泛型具体类型。

因为这种情况下, 一旦实现MySet, 因为MySet指定了继承泛型的具体类型, 在JVM 中MyBase也会被实例化。

但是这个方案一样不好, 不灵活是其次, 我都会指定了具体泛型类型了, 何必用再用getEClass()去获得泛型具体类型? 多次一举

  @Test
    void testGetEClass2() {
        MySet myset = new MySet();
        log.info("Set E class is {}",myset.getEClass());
    }

3. 构造方法方案

这也是外网强烈推荐的方案

public class MyMap<E> {

    private Class<E> eClass;

    public MyMap(Class<E> eClass){
        this.eClass = eClass;
    }

    public Class<E> getEClass(){
        return this.eClass;
    }

}

让开发人员在初始化时,顺便外部传入泛型的类, 不过手抖写错的风险…

测试方法:

  @Test
    void testGetEClass3() {
        MyMap<String> myMap= new MyMap<>(String.class);
        log.info("Set E class is {}",myMap.getEClass());
    }
}

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • java基于Apache FTP实现文件上传、下载、修改文件名、删除

    java基于Apache FTP实现文件上传、下载、修改文件名、删除

    本篇文章主要介绍了Apache FTP实现文件上传、下载、修改文件名、删除,实现了FTP文件上传(断点续传)、FTP文件下载、FTP文件重命名、FTP文件删除等功能,有需要的可以了解一下。
    2016-11-11
  • 带你深入理解MyBatis缓存机制

    带你深入理解MyBatis缓存机制

    缓存是一般的ORM框架都会提供的功能,目的就是提升查询的效率和减少数据库的压力,跟Hibernate 一样,MyBatis 也有一级缓存和二级缓存,并且预留了集成第三方缓存的接口,这篇文章主要给大家介绍了关于MyBatis缓存机制的相关资料,需要的朋友可以参考下
    2021-10-10
  • java的Jackson框架实现轻易转换JSON

    java的Jackson框架实现轻易转换JSON

    本篇文章主要介绍了java的Jackson框架实现轻易转换JSON,Jackson将Java对象转换成json对象和xml文档,同样也可以将json、xml转换成Java对象,有兴趣的可以了解一下。
    2017-02-02
  • 解读maven项目中Tomcat10与JSTL的问题汇总(Debug亲身经历)

    解读maven项目中Tomcat10与JSTL的问题汇总(Debug亲身经历)

    这篇文章主要介绍了解读maven项目中Tomcat10与JSTL的问题汇总(Debug亲身经历),具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-07-07
  • SpringBoot详细介绍SPI机制示例

    SpringBoot详细介绍SPI机制示例

    这篇文章主要介绍了深入解析Spring Boot的SPI机制详情,SPI是JDK内置的一种服务提供发现机制,可以用来启用框架扩展和替换组件,主要用于框架中开发,更多相关介绍,感兴趣的小伙伴可以参考一下下面文章内容
    2022-08-08
  • spring boot中的properties参数配置详解

    spring boot中的properties参数配置详解

    这篇文章主要介绍了spring boot中的properties参数配置,需要的朋友可以参考下
    2017-09-09
  • 新版IDEA使用Spring Initializr创建工程的两种方法

    新版IDEA使用Spring Initializr创建工程的两种方法

    这篇文章主要介绍了新版IDEA使用Spring Initializr创建工程(两种方法,官方工具和IDEA),文中通过代码示例和图文结合的方式给大家讲解的非常详细,具有一定的参考价值,需要的朋友可以参考下
    2024-10-10
  • Java实现汽车租赁系统

    Java实现汽车租赁系统

    这篇文章介绍了Java实现汽车租赁系统的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-03-03
  • macOS查看与安装Java JDK的完整步骤

    macOS查看与安装Java JDK的完整步骤

    本文详细介绍了在macOS上查看、安装、配置和管理Java JDK的步骤,包括使用官网下载、Homebrew、SDKMAN和IntelliJ IDEA内置JDK等方法,同时,还涵盖了环境变量配置、多版本管理以及常见问题解决等,需要的朋友可以参考下
    2026-03-03
  • IDEA创建Java项目保姆级教程(超详细!)

    IDEA创建Java项目保姆级教程(超详细!)

    这篇文章主要给大家介绍了关于IDEA创建Java项目保姆级教程的相关资料,Java是一种广泛使用的编程语言,广泛用于Web应用程序和客户端应用程序的开发,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2023-09-09

最新评论