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 小时前
【java开发常见错误】5、HTTP调用避坑指南:超时、重试、并发,一个都不能少
java·开发语言·后端·http·架构师·http调用·后端开发错误
iPadiPhone3 小时前
Java 泛型与通配符全链路解析及面试进阶
java·开发语言·后端·面试
无心水3 小时前
【文档解析】4、跨平台文档解析:JS/Go/C#全攻略
javascript·后端·golang·c#·架构师·大数据分析·分布式系统利器
清汤饺子3 小时前
用了大半年 Claude Code,我总结了 16 个实用技巧
前端·javascript·后端
ん贤6 小时前
Go channel 深入解析
开发语言·后端·golang
changhong19869 小时前
如何在 Spring Boot 中配置数据库?
数据库·spring boot·后端
月月玩代码11 小时前
Actuator,Spring Boot应用监控与管理端点!
java·spring boot·后端
XPoet12 小时前
AI 编程工程化:Skill——给你的 AI 员工装上技能包
前端·后端·ai编程
码事漫谈13 小时前
从“功能实现”到“深度优化”:金仓数据库连接条件下推技术的演进之路
后端
码事漫谈13 小时前
数据库查询优化中的谓词下推策略与成本感知优化实践
后端