Java在加入泛型之后,仅仅Class已经不足以描述数据的类型了,比如List<String>类型的数据,其Class的类型为List.class,但是其类型包含了泛型参数,所以java引入了Type类型来描述泛型类型。除了泛型类型,还有数组格式的数据,其类型也包含两部分,一部分是数组对象本身的class,另外一部分是数组中数据的类型。本文会详细介绍JavaType中的各种类型,分析这些类型的使用方法。

Type介绍

Type是Java 编程语言中所有类型的公共高级接口,也就是Java中所有"类型"的接口。官方原话定义如下

> 官方文档:Type is the common superinterface for all types in the Java programming language. These include raw types, parameterized types, array types, type variables and primitive types.

这样的官方描述有点难懂,此处我画个图解释一下。Type其实是和泛型一起出现的,可以说Type就是为了支持泛型。

  • 泛型出现之前,我们可以通过Class来确认一个对象的类型,比如ClassA A,那么A的类型就是ClassA;
  • 泛型出现之后,显然不能通过Class唯一确认一个对象的类型,比如List<ClassA> A,A的Class是List,但是A的类型显然不仅仅是List,它是由Class类型的List + TypeVariables的ClassA联合确认的一个Type。

> A type variable is an unqualified identifier used as a type in class, interface, method, and constructor bodies.

Type的类型

Type可以分为两大类:包含TypeVariables和不包含TypeVariables的类型:

  • 不包含TypeVariable:包含基本数据类型(int, long等),基本Class(如Object,不包含泛型的类);

  • 包含TypeVariable,按照包含的TypeVariable又分为以下几类:

    • ParameterizedType: 表示一种参数化的类型,如List<String>,泛型的参数已经指定;
    • GenericArrayType: 表示一种元素类型是参数化类型或者类型变量的数组类型,如List<String>[][];
    • WildcardType: 代表一种通配符类型表达式,比如List<?>, List<? extends ClassA>, List<? super Object>。

继续介绍Type之前,需要先介绍一下java的泛型机制:

泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。 Java语言引入泛型的好处是安全简单。泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,以提高代码的重用率。

泛型信息只存在于代码编译阶段,在进入 JVM 之前,与泛型相关的信息会被擦除掉,专业术语叫做类型擦除。

参数化类型ParameterizedType

参数化类型的写法如下:C<T1,...,Tn>,其中C是Class类型,<T1,...,Tn> 是Type,先列几个参数化类型的合法定义:

Seq\<String\>
Seq\<Seq\<String\>\>
Seq\<String\>.Zipper\<Integer\>
Pair\<String,Integer\>

ParameterizedType类型的接口方法介绍:

返回值 方法名称 描述信息
Type[] getActualTypeArguments() 参数化类型中的TypeVariable参数类型,如List<String> 返回 String.class, List<List<<String>> 返回List<<String>
Type getOwnerType() 获取当前Type所属的Type,比如对于O<T>.I<S>中的I<S>类型,会返回 O<T>
Type getRawType() 获取当前Type的Class,如List<String> 返回 List.class

>ParameterizedType represents a parameterized type such as Collection<String>.A parameterized type is created the first time it is needed by a reflective method, as specified in this package. When a parameterized type p is created, the generic type declaration that p instantiates is resolved, and all type arguments of p are created recursively. See TypeVariable for details on the creation process for type variables. Repeated creation of a parameterized type has no effect. Instances of classes that implement this interface must implement an equals() method that equates any two instances that share the same generic type declaration and have equal type parameters.

数组类型GenericArrayType

数组泛型类型的写法如下:C<T>[],其中C是Class类型,<T> 是Type,先列几个数组泛型类型的合法定义:

List\<String\>[]
List\<Seq\<String\>\> [][]
返回值 方法名称 描述信息
Type getGenericComponentType() 数组元素的类型,如List<String> []返回List<String>

注意:<>不能出现在数组的初始化中,即new数组之后不能出现<>,否则javac无法通过。但是作为引用变量或者方法的某个参数是完全可以的。不包含泛型的数组本节不做介绍(如String[]),下文中会进行介绍。

>GenericArrayType represents an array type whose component type is either a parameterized type or a type variable.

通配符类型WildcardType

通配符类型何其字面意思相同,其泛型类型不再是一个具体的类,而是一个通配符表达式,表达式包含以下三种:"?","? extends Type", "? super Type",其中Type可以为WildcardType,GenericArrayType,ParameterizedType,Class.

>WildcardType represents a wildcard type expression, such as ?, ? extends Number, or ? super Integer.

WildcardType 接口的方法和介绍如下.

返回值 方法名称 描述信息
Type[] getLowerBounds() 返回通配Type的下限类型,现阶段返回值的长度为1
Type[] getUpperBounds() 返回通配Type的上限类型,现阶段返回值的长度为1

基本Class、基本数据类型和数组

通过反射获取基本的Class和基本数据类型此处就不详细介绍了,接下来会重点介绍一下数组类型。java的数组类型由虚拟机生成,虚拟机生成的数组类型的名称一般类似于"class [[Ljava.lang.String;",注意其中的"[["表示是二维数组。那么如何获取数组中的元素类型呢? java.lang.Class包中提供了以下接口查询:

返回值 方法名称 描述信息
Class<?> componentType() 如果类型是数组类型,返回数组中元素的类型,否则返回null

>componentType():Returns the component type of this Class, if it describes an array type, or null otherwise.

如何获取字段或参数的Type信息

平时使用java程序的过程中,我们接触到的最多的类型只有Class,像泛型类型和数组类型,通常只有通过反射才能获取到。

获取字段的泛型信息

如下程序中,我们首先定义了一个自定义的类TestParameterizedType,只包含一个字段List<String> field,然后我们在另外一个单测实例中尝试通过反射获取field的相关信息。通过field.getType()我们获取到了field的类型。通过field.getGenericType()我们获取到了field的泛型信息。

public class ReflectParameterizedTypeTest {

    public static class TestParameterizedType {
private List\<String\> field;
} @Test
public void testIntType() throws NoSuchFieldException {
Class\<?\> clazz = TestParameterizedType.class;
Field field = clazz.getDeclaredField("field"); // 此处获取到字段的实际Class类型
Class\<?\> clazzType = field.getType();
System.out.println("Field type: " + clazzType.getName()); // 此处获取到字段的泛型类型
Type genericType = field.getGenericType();
System.out.println("Field generic type: " + field.getGenericType().getTypeName());
}
}

获取方法参数的泛型信息

类似于字段的获取方式,方法可以通过Method.getGenericParameterTypes()获取所有参数的泛型信息。

获取运行时变量的泛型信息

不可能,具体原因参考java的泛型擦除原理。

本文大多数内容参考了java官方文档,点此直达JAVA15官方文档地址

我是御狐神,欢迎大家关注我的微信公众号

本文最先发布至微信公众号,版权所有,禁止转载!

java基础之反射类型Type的更多相关文章

  1. 黑马程序员:Java基础总结----反射

    黑马程序员:Java基础总结 反射   ASP.Net+Android+IO开发 . .Net培训 .期待与您交流! 反射 反射的基石:Class类 Class类代表Java类,它的各个实例对象又分别 ...

  2. 【转】Java基础笔记 – 枚举类型的使用介绍和静态导入--不错

    原文网址:http://www.itzhai.com/java-based-notes-introduction-and-use-of-an-enumeration-type-static-impor ...

  3. Java基础之枚举类型Enum的使用

    Java基础之枚举类型Enum的使用 定义 public enum AccruedCleanEnum { SPREAD("1","发票"),OTHER(&quo ...

  4. java基础04-数据类型扩展及面试题

    java基础04-数据类型扩展及面试题讲解 public class demo02 { public static void main(String[] args){ // 一.整数拓展: 进制 二进 ...

  5. JAVA基础_反射获取泛型参数类型

    我经常会想获取参数的实际类型,在Hibernate中就利用的这一点. domain: Person.java public class Person { // 编号 private Long id; ...

  6. java 基础之 反射技术

    1. java代码 在 java 语言中最核心的就是代码的运行, 按照面向对象的思想,在调用java代码时往往需要先创建对象,再调用方法, 而写在方法中的即所谓的java 代码 一段java代码在程序 ...

  7. java基础(十一 )-----反射——Java高级开发必须懂的

    本文我们通过一个实际的例子来演示反射在编程中的应用,可能之前大家对反射的学习,仅仅是停留在概念层面,不知道反射究竟应用在哪,所以是一头雾水.相信通过这篇教程,会让你对反射有一个更深层次的认知. 概念 ...

  8. Java基础之一反射

    反射是框架设计的灵魂 (使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码))   一.反射的概述 JAVA反射机制是在运行状态中,对于任意一个类,都能够 ...

  9. Java基础之—反射

    反射是框架设计的灵魂 (使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码))   一.反射的概述 JAVA反射机制是在运行状态中,对于任意一个类,都能够 ...

随机推荐

  1. 🔥 LeetCode 热题 HOT 100(51-60)

    142. 环形链表 II 思路:快慢指针,快慢指针相遇后,慢指针回到头,快慢指针步伐一致一起移动,相遇点即为入环点 /** * Definition for singly-linked list. * ...

  2. ClickHouse入门笔记

    ClickHouse笔记 目录 ClickHouse笔记 第 1 章 ClickHouse 入门 列式储存的好处: 第 2 章 ClickHouse 的安装 第 3 章 数据类型 整型 浮点型 布尔型 ...

  3. 【FATE】设置虚拟机固定IP以及免密登录

    一.前期准备 1.VMWare上新建三个Centos7的虚拟机 2.VMWare虚拟机的三种联网方式 1.桥接模式 -- 桥接: 默认使用VMnet0 这一种联网方式最简单,在局域网内,你的主机是怎么 ...

  4. C# 事件与继承

    在窗体编程过程中,常常会封装一个基类,包含未来业务中常用的属性.方法.委托.事件等,但是事件作为一个特殊的委托,只能在声明类中调用,派生类都不可以调用,所以在基类中必须实现一个虚函数,实现事件的调用, ...

  5. Go interface 原理剖析--类型转换

    hi, 大家好,我是 haohognfan. 可能你看过的 interface 剖析的文章比较多了,这些文章基本都是从汇编角度分析类型转换或者动态转发.不过随着 Go 版本升级,对应的 Go 汇编也发 ...

  6. GooseFS助力大数据业务数倍提升计算能力

    前言 GooseFS是由腾讯云推出的一款分布式缓存方案,主要针对包括需要缓存加速的数据湖业务场景,提供基于对象存储COS服务的近计算端数据加速层. GooseFS 基于开源大数据缓存方案 Alluxi ...

  7. ElasticSearch进阶检索

    ElasticSearch进阶检索 入门检索中讲了如何导入elastic提供的样本测试数据,下面我们用这些数据进一步检索 一.SearchAPI ES 支持两种基本方式检索 : 1.一种是通过使用 R ...

  8. Android面试6家一线大厂,这个问题是必问!

    年后面了六家大厂,每家都会问的一个问题就是Android的消息机制!可见Android的消息机制是多么重要! 消息机制之所以这么重要是因为Android应用程序是通过消息来驱动的,Android某种意 ...

  9. 【LeetCode】860. 柠檬水找零

    860. 柠檬水找零 知识点:贪心 题目描述 在柠檬水摊上,每一杯柠檬水的售价为 5 美元. 顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯. 每位顾客只买一杯柠檬水,然后向你付 ...

  10. 从官网下载历史版本的java

    下载历史版本的java 因为一些bug需要降低java版本来尝试解决,但是好多都要收费,我就搞不明白了,官网都有免费的我要你的收费软件干嘛 首先直接搜索java,进入Oracle,或者 Java SE ...