Java获取泛型类型信息

这篇具有很好参考价值的文章主要介绍了Java获取泛型类型信息。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

根据使用泛型位置的不同可以分为:声明侧泛型、使用侧泛型。

声明侧的泛型信息被记录在Class文件的Constant pool中以Signature的形式保存。而使用侧的泛型信息并没有保存。

声明侧泛型
声明侧泛型包括:

泛型类,或泛型接口的声明
带有泛型参数的成员变量
带有泛型参数的方法
使用侧泛型
使用侧泛型包括:

方法的局部变量,
方法调用时传入的变量
获取泛型类型相关方法
上文有提到,声明侧的泛型被记录在Class文件的Constant pool中以Signature的形式保存。

JDK的Class、Field、Method类提供了一系列的获取泛型类型的相关方法。

1. Class类的泛型方法
Type getGenericSuperclass():获取父类的Type

若父类有泛型,返回的实际Type是ParameterizedType接口的实现类ParameterizedTypeImpl类
若父类无泛型,返回的实际Type是Class类
Type[] getGenericInterfaces():获取父接口的Type集合

若父类有泛型,返回的实际Type是ParameterizedType接口的实现类ParameterizedTypeImpl类
若父类无泛型,返回的实际Type是Class类
2. Field类的泛型方法
Type getGenericType():获取字段的Type

若字段有泛型,返回的实际Type是ParameterizedType接口的实现类ParameterizedTypeImpl类
若字段无泛型,返回的实际Type是Class类
3. Method类的泛型方法
Type getGenericReturnType():获取方法返回值的Type

若返回值有泛型,返回的实际Type是ParameterizedType接口的实现类ParameterizedTypeImpl类
若返回值无泛型,返回的实际Type是Class类
Type[] getGenericParameterTypes():获取方法参数的Type集合

若方法参数有泛型,返回的实际Type是ParameterizedType接口的实现类ParameterizedTypeImpl类
若方法参数无泛型,返回的实际Type是Class类
Type[] getGenericExceptionTypes():获取方法声明的异常的Type集合

若方法参数有泛型,返回的实际Type是ParameterizedType接口的实现类ParameterizedTypeImpl类
若方法参数无泛型,返回的实际Type是Class类
4. ParameterizedType类
ParameterizedType是Type的子接口,表示参数化类型,用于获取泛型的参数类型。

ParameterizedType的主要方法:

Type[] getActualTypeArguments():获取实际类型参数的Type集合

Type getRawType():获取声明此类型的类或接口的Type

Type getOwnerType():如果声明此类型的类或接口为内部类,这返回的是该内部类的外部类的Type(也就是该内部类的拥有者)

获取声明侧的泛型类型信息
泛型类,或泛型接口的声明
带有泛型参数的成员变量
带有泛型参数的方法
示例:

public class MyTest extends TestClass<String> implements TestInterface1<Integer>,TestInterface2<Long> {

    private List<Integer> list;

    private Map<Integer, String> map;

    public List<String> aa() {
        return null;
    }

    public void bb(List<Long> list) {

    }

    public static void main(String[] args) throws Exception {
        System.out.println("======================================= 泛型类声明的泛型类型 =======================================");
        ParameterizedType parameterizedType = (ParameterizedType)MyTest.class.getGenericSuperclass();
        System.out.println(parameterizedType.getTypeName() + "--------->" + parameterizedType.getActualTypeArguments()[0].getTypeName());

        Type[] types = MyTest.class.getGenericInterfaces();
        for (Type type : types) {
            ParameterizedType typ = (ParameterizedType)type;
            System.out.println(typ.getTypeName() + "--------->" + typ.getActualTypeArguments()[0].getTypeName());
        }

        System.out.println("======================================= 成员变量中的泛型类型 =======================================");
        ParameterizedType parameterizedType1 = (ParameterizedType)MyTest.class.getDeclaredField("list").getGenericType();
        System.out.println(parameterizedType1.getTypeName() + "--------->" + parameterizedType1.getActualTypeArguments()[0].getTypeName());

        ParameterizedType parameterizedType2 = (ParameterizedType)MyTest.class.getDeclaredField("map").getGenericType();
        System.out.println(parameterizedType2.getTypeName() + "--------->" + parameterizedType2.getActualTypeArguments()[0].getTypeName()+","+parameterizedType2.getActualTypeArguments()[1].getTypeName());

        System.out.println("======================================= 方法参数中的泛型类型 =======================================");
        ParameterizedType parameterizedType3 = (ParameterizedType)MyTest.class.getMethod("aa").getGenericReturnType();
        System.out.println(parameterizedType3.getTypeName() + "--------->" + parameterizedType3.getActualTypeArguments()[0].getTypeName());

        System.out.println("======================================= 方法返回值中的泛型类型 =======================================");
        Type[] types1 = MyTest.class.getMethod("bb", List.class).getGenericParameterTypes();
        for (Type type : types1) {
            ParameterizedType typ = (ParameterizedType)type;
            System.out.println(typ.getTypeName() + "--------->" + typ.getActualTypeArguments()[0].getTypeName());
        }
    }
}

class TestClass<T> {

}

interface TestInterface1<T> {

}

interface TestInterface2<T> {

}


输出

======================================= 泛型类声明的泛型类型 =======================================
com.joker.test.generic.TestClass<java.lang.String>--------->java.lang.String
com.joker.test.generic.TestInterface1<java.lang.Integer>--------->java.lang.Integer
com.joker.test.generic.TestInterface2<java.lang.Long>--------->java.lang.Long
======================================= 成员变量中的泛型类型 =======================================
java.util.List<java.lang.Integer>--------->java.lang.Integer
java.util.Map<java.lang.Integer, java.lang.String>--------->java.lang.Integer,java.lang.String
======================================= 方法参数中的泛型类型 =======================================
java.util.List<java.lang.String>--------->java.lang.String
======================================= 方法返回值中的泛型类型 =======================================
java.util.List<java.lang.Long>--------->java.lang.Long



获取使用侧的泛型类型信息
上面讲的相关类的获取泛型类型相关方法都只是针对声明侧的泛型。因为声明侧的泛型被记录在Class文件的Constant pool中以Signature的形式保存。所以Java提供了相关方法能获取到这些信息。

那使用侧的泛型信息怎么获取呢?由于使用侧的泛型信息在编译期的时候就被类型擦除了,所以运行时是没办法获取到这些泛型信息的。

难道就真的没办法了吗,其实还是有的。使用侧需要获取泛型信息的地方主要是:方法调用时传入的泛型变量,通常需要在方法中获取变量的泛型类型。比如在JSON解析(反序列化)的场景,他们是怎么实现的了。

针对获取使用侧的泛型类型信息,主要实现方案是通过匿名内部类。

Gson中的泛型抽象类TypeToken<T>,FastJson中的泛型类TypeReference<T>等就是用的该方案。

匿名内部类实现获取使用侧的泛型类型
上文有讲到,在声明侧的泛型中,针对泛型类或泛型接口的声明的泛型,Class类提供了getGenericSuperclass()、getGenericInterfaces()来获取其子类(实现类)上声明的具体泛型类型信息。

而匿名内部类是什么?其本质就是一个继承/实现了某个类(接口,普通类,抽象类)的子类匿名对象。

匿名内部类实现获取使用侧的泛型类型的原理:

定义泛型类,泛型类中有一个Type类型的字段,用于保存泛型类型的Type
通过匿名内部类的方式创建该泛型类的子类实例(指定了具体的泛型类型)
在创建子类实例的构造方法中,已经通过子类的Class的getGenericSuperclass()获取到了泛型类型信息并复制给了Type类型的字段中。
随后任何地方,只要得到了该子类实例,就可以通过实例得到泛型类型的Type,这就得到了使用侧的泛型类信息。
简单示例:

定义泛型类TestClass2<T>,类中包含字段Type

public abstract class TestClass2<T> {

    private final Type type;

    public TestClass2() {
        Type superClass = getClass().getGenericSuperclass();
        if (!(superClass instanceof ParameterizedType)) {
            throw new IllegalArgumentException("无泛型类型信息");
        }
        type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
    }

    public Type getType() {
        return type;
    }
}



测试获取泛型类型文章来源地址https://www.toymoban.com/news/detail-700995.html

public class Test {

    public static  <T> T get(TestClass2<T> tTestClass2) throws IllegalAccessException, InstantiationException {
        Type type = tTestClass2.getType();
        Class clazz = (Class) type;
        return (T)clazz.newInstance();
    }

    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
        String str = get(new TestClass2<String>() {});
        Date date = get(new TestClass2<Date>() {});
    }
}

到了这里,关于Java获取泛型类型信息的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java中泛型的详细介绍

    引言:         Java语言中的泛型是一种强大的特性,它允许我们在编写代码时指定类、接口和方法的参数类型。通过使用泛型,我们可以提高代码的重用性、可读性和安全性。在本博客中,我们将详细介绍Java中泛型的知识。         泛型是Java 5中引入的一个新特性。

    2024年01月18日
    浏览(36)
  • Java泛型的继承和通配符

    继承 两个容器所容纳的类类型是有子类父类的关系的 但是容器之间没有 反证法: 假设做法成立 list1=list2 list 指向list2的容器实例 list1.add(123)可以成立,明显标注 String 后是不行的 所以 类SuperA是类A的父类,则 GSuperA 与 GA 是并列关系没有子父关系 类SuperA是类A的父类或接口

    2024年01月17日
    浏览(40)
  • 【java数据结构】泛型的初步认识(2)

    hellohello~,大家好💕💕,这里是E绵绵呀✋✋ ,如果觉得这篇文章还不错的话还请点赞❤️❤️收藏💞 💞 关注💥💥,如果发现这篇文章有问题的话,欢迎各位评论留言指正,大家一起加油!一起chin up!👍👍  💥 个人主页: E绵绵的博客 💥 所属专栏: JAVA知识点专栏

    2024年04月26日
    浏览(36)
  • kotlin获取泛型集合的类型信息

    通过  reified 和内联函数来实现 注:将reified 和 inline去掉就无法通过T::class.java获取到类型,因为编译的时候会进行类型擦除,所以在运行的时候已经无法获取到类型了,这是Java兼容性的处理机制,kotlin通过reified和inline优化了泛型,实现了运行时获取类型 。 Java 5才引

    2024年02月14日
    浏览(38)
  • Scala中的类型检查和转换,以及泛型,scala泛型的协变和逆变

    说明 (1) obj.isInstanceOf[T]:判断 obj 是不是T 类型。 (2) obj.asInstanceOf[T]:将 obj 强转成 T 类型。 (3) classOf 获取对象的类名。 案例 1.说明 (1)枚举类:需要继承 Enumeration (2)应用类:需要继承App 2. 案例 1.说明 使用 type 可以定义新的数据数据类型名称,本质上就

    2024年02月10日
    浏览(41)
  • 每个.NET开发都应掌握C#泛型的知识点

    C#泛型编程是.NET framework 2.0的新特征,它提高了代码安全性和代码重用的问题。由于泛型必须指定类型,正确的使用可以避免了装箱拆箱的问题;使用了泛型后,可以将算法或组件泛型化,基于类型参数支持任意数据类型,从而提高了代码的重用性。 C#泛型编程在C#是很重要的特

    2024年02月15日
    浏览(48)
  • Java泛型:灵活多变的类型参数化工具

    👑专栏内容:Java ⛪个人主页:子夜的星的主页 💕座右铭:前路未远,步履不停 在传统的编程方法中,类和方法通常被限定为使用特定的类型。这些类型可能是基础的数据类型(如整数、字符等),或者是由程序员自己定义的复杂类型。这种方式在处理单一类型数据时很有

    2024年02月01日
    浏览(61)
  • Java中泛型和Object类型 初级进阶教程(一)

    在学习的过程中,常常看到某个类或者接口等中使用 ListT, TestT,其中T的作用是什么呢? 1 在类中使用泛型 2 使用多个泛型 3 在类中使用泛型 4 在方法中使用泛型 5 限制泛型类型 6 通配符 (Wildcard) 总结:泛型和Object类型之间的区别 类型安全: 泛型 T : 泛型提供了编译时类型

    2024年02月01日
    浏览(54)
  • 第8章-第1节-Java中的泛型(参数化类型)

    1、泛型在java中有很重要的地位,在面向对象编程及各种设计模式中有非常广泛的应用。什么是泛型?为什么要使用泛型? 2、概念:在类声明体中用到了类型参数。 3、泛型类只支持类类型,不支持基本数据类型(如int),但可以用包装类(如Integer ) 泛型标识 含义 T Type 类

    2024年01月23日
    浏览(45)
  • 01 java 学习 数据类型、基础语法、封装、继承、多态、接口、泛型、异常等

    目录 环境搭建和基础知识  什么是JRE: 什么是JDK: 基础数据类型  分支选择if else switch和c一毛一样 for和while循环还有数组基本和c一样 封装 函数调用、传参、命名规范、数组新命名规范 java输入Scanner scanner = new Scanner(System.in); 类的创建和使用以及封装修饰符  构造方法:含义、

    2024年02月11日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包