1. Type接口简介

Type 是 Java 编程语言中所有类型的公共高级接口。它们包括原始类型、参数化类型、数组类型、类型变量和基本类型。(从JDK1.5开始使用。)

Type体系中类型的包括:

  • 原始类型(Type):不仅仅包含我们平常所指的类,还包括枚举、数组、注解等
  • 参数化类型(ParameterizedType):就是我们平常所用到的泛型List、Map<K,V>、Set、Class<?>
  • 数组类型(GenericArrayType):并不是我们工作中所使用的数组 String[] 、byte[],而是带有泛型的数组,即T[]
  • 类型变量(TypeVariable):比如 T a
  • 基本类型(Class):原始类型,每个类(貌似接口也有)都会有个 Class 对象
  • 通配符表达式,或泛型表达式,它虽然是 Type 的一个子接口,但并不是 Java 类型中的一种,表示的仅仅是类似 ? extends T、? super K这样的通配符表达式。

Type

本文参考贾博岩我眼中的Java-Type体系

2. 获取Type类型

获取Type类型对象

  1. 调用 Class.getGenericInterfaces()方法获取该类实现接口的 Type 类型列表。
  2. 调用 Class.getDeclaredFields()方法获取该类 File 字段列表。调用 File.getGenericType()方法得到这个属性的 Type类 型。
  3. 调用 Method.getGenericParameterTypes()方法获得获取该方法参数 Type 类型列表。

3. Type的子接口

3.1 ParameterizedType

ParameterizedType

参数化类型,即泛型;例如:List<T>、Map<K,V>等带有参数化的对象
ParameterizedType接口中,有3个方法,分别是 getActualTypeArguments()、 getRawType()、 getOwnerType();

1
2
3
4
5
6
7
8
9
10
11
public interface ParameterizedType extends Type {

/** 获取范型 <> 中的实际类型 */
Type[] getActualTypeArguments();

/** 获取范型 <> 前面的实际类型 */
Type getRawType();

/** 获取该类型所属,没有返回🈳️ */
Type getOwnerType();
}

3.1.1 getActualTypeArguments

获取泛型中的实际类型,可能会存在多个泛型,例如Map<K,V>,所以会返回Type[]数组;

ParameterizedType-getActualTypeArguments

值得注意的是,无论<>中有几层嵌套(List<Map<String,Integer>),getActualTypeArguments()方法永远都是脱去最外层的<>(也就是List<>),将括号内的内容(Map<String,Integer>)返回;

我们经常遇到的 List,通过 getActualTypeArguments() 方法,得到的返回值是 TypeVariableImpl 对象,也就是 TypeVariable 类型(后面介绍);

3.1.2 getOwnerType

获取声明泛型的类或者接口,也就是泛型中<>前面的那个值;

ParameterizedType-getOwnerType

3.1.3 getRawType

ParameterizedType-getRawType

通过方法的名称,我们大概了解到,此方法是获取泛型的拥有者,那么拥有者是个什么意思?

Returns a {@code Type} object representing the type that this type    * is a member of.  For example, if this type is {@code O.I},    * return a representation of {@code O}.  (摘自JDK注释)

通过注解,我们得知,“拥有者”表示的含义–内部类的“父类”,通过 getOwnerType()方法可以获取到内部类的“拥有者”;例如: Map  就是 Map.Entry<String,String> 的拥有者;

3.2 GenericArrayType

GenericArrayType

泛型数组类型,用来描述ParameterizedTypeTypeVariable类型的数组;即 List<T>[] 、T[]等
GenericArrayType接口中,仅有1个方法,就是 getGenericComponentType()

1
2
3
4
5
public interface GenericArrayType extends Type {

/** 获得这个数组元素类型,即获得: A<T> (A<T>[]) 或 (T[]) */
Type getGenericComponentType();
}

3.2.1 getGenericComponentType

返回泛型数组中元素的Type类型,即 List<String>[] 中的 List<String>(ParameterizedTypeImpl)、T[] 中的T(TypeVariableImpl)

GenericArrayType-getGenericComponentType

值得注意的是,无论是几维数组,getGenericComponentType() 方法都只会脱去最右边的[],返回剩下的值

3.3 TypeVariable

TypeVariable

类型变量,即泛型中的变量;例如:T、K、V等变量,可以表示任何类;在这需要强调的是,TypeVariable代表着泛型中的变量,而ParameterizedType则代表整个泛型
TypeVariable接口中,有4个方法,分别为 getBounds()、getGenericDeclaration()、getAnnotatedBounds、getName()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public interface TypeVariable<D extends GenericDeclaration> extends Type, AnnotatedElement {

/** 获取范型上限,无显式定义(extends),默认为Object */
Type[] getBounds();

/** 获得声明该类型变量的实体(获得类、方法或者构造器) */
D getGenericDeclaration();

/** 获得名称,即K、V、E之类的 */
String getName();

/** 获取类型变量上限的对象数组 */
AnnotatedType[] getAnnotatedBounds();
}

3.3.1 getBounds

获得该类型变量的上限(上边界),若无显式定义(extends),默认为 Object,类型变量的上限可能不止一个,因为可以用&符号限定多个(这其中有且只能有一个为类或抽象类,且必须放在extends后的第一个,即若有多个上边界,则第一个&后必为接口)。

TypeVariable-getBounds

无显式定义extends:

TypeVariable-getBounds

值得注意的是,类型变量的上限可以为多个,必须使用&符号相连接,例如 List<T extends Number & Serializable>;其中,& 后必须为接口

3.3.2 getGenericDeclaration

获取声明该类型变量实体,也就是 TypeVariableTest<T> 中的TypeVariableTest

TypeVariable-getGenericDeclaration

3.3.3 getAnnotatedBounds

返回一个AnnotatedType对象的数组,表示使用类型来表示此TypeVariable表示的类型参数的上限。 数组中的对象的顺序对应于 type 参数的声明中的边界的顺序。 如果 type 参数声明没有边界,则返回长度为 0 的数组。

3.3.4 getName

获取类型变量在源码中定义的名称

TypeVariable-getName

说到TypeVariable类,就不得不提及 Java-Type 体系中另一个比较重要的接口—GenericDeclaration。含义为:声明类型变量的所有实体的公共接口;也就是说该接口定义了哪些地方可以定义类型变量(泛型)

通过查看源码发现,GenericDeclaration下有四个子类,分别为 Class、Executable、Method、Constructor。其中 Method、Constructor 继承自 Executable 表示可执行。

GenericDeclaration

此时,我们不禁要问,我们不是经常在类中的属性声明泛型吗,怎么 Field 没有实现GenericDeclaration接口呢?

其实,我们在 Field 中并没有声明泛型,而是在使用泛型而已!不信,我们实际上代码来看看!

  1. 首先在 Class 上定义泛型:

GenericDeclaration-Class

  1. 我们没有在 Class 上定义泛型,直接在构造方法上定义泛型:

GenericDeclaration-Constructor

  1. 我们直接在属性上定义:

GenericDeclaration-Field

我们看到,如果不在 Class 上定义,属性上并不能直接使用!所以,这也是我之前说的属性上并不是定义泛型,而是使用泛型,所以 Field 并没有实现GenericDeclaration接口!

3.4 WildcardType

WildcardType

?—通配符表达式,表示通配符泛型,但是WildcardType并不属于 Java-Type 中的一种。例如:List<? extends Number> 和 List<? super Integer>

1
2
3
4
5
6
7
8
public interface WildcardType extends Type {
/** 获取范型表达式上界(上限extends) */
Type[] getUpperBounds();

/** 获取范型表达式下界(下限super) */
Type[] getLowerBounds();

}

WildcardType接口中,有2个方法,分别为 getUpperBounds()、getLowerBounds()

3.4.1 getUpperBounds

获取泛型变量的上边界(extends)

WildcardType-getUpperBounds

3.4.2 getLowerBounds

获取泛型变量的下边界(super)

WildcardType-getLowerBounds

4. Type 的实现 Class

Type接口的实现类,是我们工作中常用到的一个对象;在 Java 中,每个 .class 文件在程序运行期间,都对应着一个Class对象,这个对象保存有这个类的全部信息;因此,Class对象也称之为 Java 反射的基础

Class

通过上面的例子,可以看出,当我们没有声明泛型的时候,我们普通的对象就是一个 Class 类型,是 Type 中的一种