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/...

相关推荐
励志成为架构师10 分钟前
跟小白一起领悟Thread——如何开启一个线程(上)
java·后端
hankeyyh11 分钟前
golang 易错点-slice copy
后端·go
考虑考虑20 分钟前
Redis事务
redis·后端
Victor35641 分钟前
Redis(6)Redis的单线程模型是如何工作的?
后端
Victor35642 分钟前
Redis(7)Redis如何实现高效的内存管理?
后端
David爱编程2 小时前
进程 vs 线程到底差在哪?一文吃透操作系统视角与 Java 视角的关键差异
后端
smileNicky12 小时前
SpringBoot系列之从繁琐配置到一键启动之旅
java·spring boot·后端
David爱编程13 小时前
为什么必须学并发编程?一文带你看懂从单线程到多线程的演进史
java·后端
long31613 小时前
java 策略模式 demo
java·开发语言·后端·spring·设计模式
rannn_11114 小时前
【Javaweb学习|黑马笔记|Day1】初识,入门网页,HTML-CSS|常见的标签和样式|标题排版和样式、正文排版和样式
css·后端·学习·html·javaweb