Java中的Type详解

1、Type

Type是Java编程语言中所有类型的公共超接口。这些类型包括原始类型、参数化类型、数组类型、类型变量和基本类型。

  • 1.1、getTypeName

返回描述此类型的字符串,包括有关任何类型参数的信息。

2、ParameterizedType:参数化类型

参数化类型,即泛型;例如:List、Map<K,V>等带有参数化的对象;

  • 2.1、getActualTypeArguments:Type

获取<>中实际类型

  • 2.2、 getOwnerType(): Type

返回ParameterizedType类型所在的类的Type。如Map.Entry<String, Object>这个参数化类型返回的事Map(因为Map.Entry这个类型所在的类是Map)的类型。

  • 2.3、 getRawType(): Type[]

获取<>前面实际类型

java 复制代码
public class TestParameterizedTypeBean {
    //是ParameterizedType
    private HashMap<String, Object> map;
    private HashSet<List<String>> set;
    public static void main(String[] args) {
        getParameterizedTypeWithName("map");
        getParameterizedTypeWithName("set");
    }
    private static void getParameterizedTypeWithName(String name){
        Field f;
        try {
            //利用反射得到TestParameterizedTypeBean类中的所有变量
            f = TestParameterizedTypeBean.class.getDeclaredField(name);
            f.setAccessible(true);
            Type type = f.getGenericType();
            if (type instanceof ParameterizedType){
                System.out.println("--------start---" + f.getName()+"------------------");
                for(Type param : ((ParameterizedType)type).getActualTypeArguments()){
                    //打印实际参数类型
                    System.out.println("---type actualType---" + param.toString());
                }
                //打印所在的父类的类型
                System.out.println("---type ownerType0---"+ ((ParameterizedType) type).getOwnerType());
                //打印其本身的类型
                System.out.println("---type rawType---"+ ((ParameterizedType) type).getRawType());
                System.out.println("--------end---" + f.getName()+"------------------");
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }

}

输出:

java 复制代码
--------start---map------------------
---type actualType---class java.lang.String
---type actualType---class java.lang.Object
---type ownerType0---null
---type rawType---class java.util.HashMap
--------end---map------------------
--------start---set------------------
---type actualType---java.util.List<java.lang.String>
---type ownerType0---null
---type rawType---class java.util.HashSet
--------end---set------------------

3、TypeVariable

类型变量, 泛型信息在编译时会被转换为一个特定的类型, 而TypeVariable就是用来反映在JVM编译该泛型前的信息.(通俗的讲,TypeVariable就是我们常用的List 、Map<K,V>中的T,K这种泛型变量)。

  • 3.1、getBounds(): Type[]

获取泛型的上限,无显式定义(extends),默认为Object

  • 3.2、getGenericDeclaration():D

获取声明该类型变量实体(即获得类、方法或构造器名)

  • 3.3、getName(): String

获得名称,即K、V、E之类名称

java 复制代码
public class TestType <K extends Comparable & Serializable, V> {
    K key;
    V value;
    public static void main(String[] args) throws Exception {
        // 获取字段的类型
        Field fk = TestType.class.getDeclaredField("key");
        Field fv = TestType.class.getDeclaredField("value");
        Assert.that(fk.getGenericType() instanceof TypeVariable, "必须为TypeVariable类型");
        Assert.that(fv.getGenericType() instanceof TypeVariable, "必须为TypeVariable类型");
        TypeVariable keyType = (TypeVariable)fk.getGenericType();
        TypeVariable valueType = (TypeVariable)fv.getGenericType();
        // getName 方法
        System.out.println(keyType.getName());                 // K
        System.out.println(valueType.getName());               // V
        // getGenericDeclaration 方法
        System.out.println(keyType.getGenericDeclaration());   // class com.test.TestType
        System.out.println(valueType.getGenericDeclaration()); // class com.test.TestType
        // getBounds 方法
        System.out.println("K 的上界:");                        // 有两个
        for (Type type : keyType.getBounds()) {                // interface java.lang.Comparable
            System.out.println(type);                          // interface java.io.Serializable
        }
		
        System.out.println("V 的上界:");                        // 没明确声明上界的, 默认上界是 Object
        for (Type type : valueType.getBounds()) {              // class java.lang.Object
            System.out.println(type);
        }
    }
}

4、GenericArrayType

泛型数组类型,用来描述ParameterizedType、TypeVariable类型的数组;即List[] 、T[]等;

  • 4.1、getGenericComponentType():Type

返回组成泛型数组的实际参数化类型,如List[] 则返回 List。

java 复制代码
    public class GenericArrayTypeTest<T> {
    // 泛型数组类型
    private T[] value;
    private List<String>[] lists;

    // 非泛型数组类型
    private List<String> list;
    private T singleValue;

    public static void main(String[] args) {
        Field[] declaredFields = GenericArrayTypeTest.class.getDeclaredFields();
        Arrays.stream(declaredFields).forEach(field -> {
            field.setAccessible(true);
            // 输出当前变量是否为GenericArrayType类型
            System.out.println("Field: " + field.getName() + "; instanceof GenericArrayType: "
                    + (field.getGenericType() instanceof GenericArrayType));
            if (field.getGenericType() instanceof GenericArrayType) {
                // 输出泛型类型
                System.out.println("Field: " + field.getName() + "; getGenericComponentType():"
                        + ((GenericArrayType) field.getGenericType()).getGenericComponentType());
            }
            field.setAccessible(false);
        });
    }
}

输出:

5、WildcardType: 通配符类型

表示通配符类型,比如 <?>, <? Extends Number>等

  • getLowerBounds(): Type[]: 得到下边界的数组
  • getUpperBounds(): Type[]: 得到上边界的type数组

注:如果没有指定上边界,则默认为Object,如果没有指定下边界,则默认为null

下面还是通过一个例子了解一下:

java 复制代码
public class TestWildcardType {

    public static void main(String[] args){
      //获取TestWildcardType类的所有方法(本例中即 testWildcardType 方法)
        Method[] methods = TestWildcardType.class.getDeclaredMethods();
        for (Method method: methods){
            //获取方法的所有参数类型
            Type[] types = method.getGenericParameterTypes();
            for (Type paramsType: types){
               System.out.println("type: " + paramsType.toString());
              //如果不是参数化类型则直接continue,执行下一个循环条件
               if (!(paramsType instanceof ParameterizedType)){
                    continue;
               }
              //将当前类型强转为参数化类型并获取其实际参数类型(即含有通配符的泛型类型)
               Type type = ((ParameterizedType) paramsType).getActualTypeArguments()[0];
              //输出其是否为通配符类型
               System.out.println("type instanceof WildcardType : " + 
                                     ( type instanceof WildcardType));
               if (type instanceof WildcardType){
                  int lowIndex = ((WildcardType) type).getLowerBounds().length - 1;
                  int upperIndex = ((WildcardType) type).getUpperBounds().length - 1;
                 //输出上边界与下边界
                  System.out.println("getLowerBounds(): "
                        + 
           (lowIndex >= 0 ? ((WildcardType) type).getLowerBounds()[lowIndex] : "String ")
                        + "; getUpperBounds(): "
                        + 
         (upperIndex >=0 ? ((WildcardType) type).getUpperBounds()[upperIndex]:"Object"));
                }
                }
        }
    }
    public void testWildcardType(List<? extends OutputStream> numberList, 
              List<? super InputStream> upperList,  List<Integer> list, InputStream inputStream){}
  }

泛型的擦除的原因以及Java中Type的作用

其实在jdk1.5之前Java中只有原始类型而没有泛型类型,而在JDK 1.5 之后引入泛型,但是这种泛型仅仅存在于编译阶段,当在JVM运行的过程中,与泛型相关的信息将会被擦除,如List与List都将会在运行时被擦除成为List这个类型。而类型擦除机制存在的原因正是因为如果在运行时存在泛型,那么将要修改JVM指令集,这是非常致命的。

此外,原始类型在会生成字节码文件对象,而泛型类型相关的类型并不会生成与其相对应的字节码文件(因为泛型类型将会被擦除),因此,无法将泛型相关的新类型与class相统一 。因此,为了程序的扩展性以及为了开发需要去反射操作这些类型,就引入了Type这个类型,并且新增了ParameterizedType, TypeVariable, GenericArrayType, WildcardType四个表示泛型相关的类型,再加上Class,这样就可以用Type类型的参数来接受以上五种子类的实参或者返回值类型就是Type类型的参数。统一了与泛型有关的类型和原始类型Class。而且这样一来,我们也可以通过反射获取泛型类型参数。

参考:

juejin.cn/post/684490...
www.cnblogs.com/linghu-java... calebzhao.github.io/2019/12/29/...

相关推荐
老马啸西风3 小时前
Occlum 是一个内存安全的、支持多进程的 library OS,特别适用于 Intel SGX。
网络·后端·算法·阿里云·云原生·中间件·golang
冯浩(grow up)8 小时前
Spring Boot 连接 MySQL 配置参数详解
spring boot·后端·mysql
Asthenia04129 小时前
面试复盘:left join 底层算法(嵌套/哈希/分块) & 主从复制(异步/半同步/同步)
后端
秋野酱9 小时前
基于javaweb的SpringBoot雪具商城系统设计与实现(源码+文档+部署讲解)
java·spring boot·后端
计算机-秋大田9 小时前
基于Spring Boot的ONLY在线商城系统设计与实现的设计与实现(LW+源码+讲解)
java·vue.js·spring boot·后端·课程设计
爱的叹息9 小时前
spring boot + thymeleaf整合完整例子
java·spring boot·后端
Asthenia041210 小时前
MySQL:意向锁与兼容性/MySQL中的锁加在什么上?/innodb中锁的底层是怎么实现的?
后端
程序猿DD_10 小时前
如何用Spring AI构建MCP Client-Server架构
java·人工智能·后端·spring·架构
小兵张健11 小时前
Cursor 嵌入产研 —— 从产品背景到后端代码实现
后端·ai编程·cursor
竹等寒11 小时前
Go红队开发—CLI框架(一)
开发语言·后端·golang