一、背景
在阅读Gson源码前需要掌握有关Java的Type类型的知识点。
二、Type类型
2.1 Java编程语言中的所有类型
Type是Java编程语言中所有类型的父接口。这里的所有的Java类型包括原生类型(raw types),参数化类型(Parameterized Types)、数组类型(GenericArray Type)、类型变量(Type Variables)和基本类型(primitive types)。
原生类型(raw types):指一般类型,如String,Number,另外还包括枚举、数组和注解等。
参数化类型(Parameterized types):表示一种参数化的类型,比如Collection,即普通的泛型。可参考List、Map。
数组类型(GenericArray Type):表示泛型定义的数组,这里的数组内中的item可以是参数化类型(parameterized types)或类型变量(type variables),但是并不是原生类型和基本类型。
类型变量(Type variables):表示类型变量,并不确定其类型,比如:V,
基本类型(primitive types): int、float、double等。
Type类型的由来
Type是在JDK1.5开始引入,引入的主要原因是因为泛型,在JDK1.5之前的版本中没有泛型只有原生类型。所有的原生类型都是通过字节码文件类Class进行抽象。Class类的一个具体对象就代表一个指定的原生对象。
在泛型出现之后,扩充了数据类型。也就是从原生类型扩充了参数化类型、类型变量类型和泛型数组类型,它们三属于Type的子接口。
此处存在一个问题,为什么这些类型没有统一到Class下,而是新增加一个Type?
一切都是为了程序的扩展性,于是最后引入了Type接口作为Class,ParameterizedType,GenericArrayType,TypeVariable和WildcardType这几种类型的总的父接口。
2.2 Type类型的子孙
Type类型UML图如下
Type直接子类
Type的直接子类只有一个,即Class,代表着Type类型中原始类型和基本类型。此处Class是Type的一种实现,是对Java类的抽象,描述的是类的信息,包括类的修饰符(public/private/protect/default/static/final等)、类的类型(一般类、枚举、注释、接口、数组等)、类的构造器、类的字段、类的方法等信息。
Class同样也是反射机制的基础,反射API通过操作Class可以获取Java程序运行期间,每个对象所属的类详细信息。虚拟机为每个类型管理一个Class对象,因此可以用==运算符实现两个类对象比较的操作。
获取class的常用方式:
1.调用getClass() Object类中的getClass()方法返回一个Class类型的实例
Boolean var1 = true;
Class<?> classType2 = var1.getClass();
System.out.println(classType2); //输出:class java.lang.Boolean
2.运用T.class 语法(T是任意的Java类型)
Class<?> classType4 = Boolean.class;
System.out.println(classType4);//输出:class java.lang.Boolean
3.运用static method Class.forName()(使用时应该提供异常处理器)
Class<?> classType5 = Class.forName("java.lang.Boolean");System.out.println(classType5);//输出:class java.lang.Boolean
4.运用primitive wrapper classes的TYPE 语法(这里返回的是原生类型,和Boolean.class返回的不同)
Class<?> classType3 = Boolean.TYPE;
System.out.println(classType3);//输出:boolean
Class常用的方法:
方法 | 说明 | 例子 |
---|---|---|
getName() | 返回类的名字 | String.class.getName(); //返回”java.lang.String” |
newInstance() | 快速地创建一个类的实例(调用默认构造器,如果该类没有默认构造器,抛出异常)(如果要为构造器提供参数,使java.lang.reflect.Constructor中的newInstance方法) | String s = “java.util.Date”;Object m = Class.forName(s).newInstance(); |
getSuperclass() | 返回超类 | |
getFields() getMethods() getConstructors()(还有带字符串参数,给定名称的形式) | 分别返回类支持的public域、方法和构造器数组,其中包括超类的公有成员 | |
getDeclaredFields() getDeclaredMethods() getDeclaredConstructors()(还有给定名称的形式) | 分别返回类中声明的全部域、方法和构造器数组。其中包括私有和保护成员,但不包括超类的成员 |
Type子接口
1. ParameterizedType
参数化类型,即泛型,官方解释是“ParameterizedType represents a parameterized type such as
Collection< String>”,需要注意的是,官方只是给了一个泛型的参照。Parameterized类型可以参考如下示例:
//ParameterizedType类型
Map<String, Person> map;
Set<String> set1;
Class<?> clz;
Holder<String> holder;
List<String> list;
static class Holder<V>{
}
//非ParameterizedType类型
Set set;
List aList;
ParameterizedType的主要方法
getActualTypeArguments
获取参数化类型<>中的类型参数的类型,因为可能有多个类型参数,例如Map< K, V>,所以返回的是一个Type[]数组。另外需要注意的地方是无论<>中存在几层<>嵌套,这个方法仅仅脱去最外层的<>,之后剩下的内容就作为这个方法的返回值,所以其返回值类型不一定。参考如下示例:
1. List<ArrayList> a1;//这里返回的是ArrayList,Class类型
2. List<ArrayList<String>> a2;//这里返回的是ArrayList<String>,ParameterizedType类型
3. List<T> a3;//返回的是T,TypeVariable类型
4. List<? extends Number> a4; //返回的是WildcardType类型
5. List<ArrayList<String>[]> a5;//返回的是GenericArrayType
getRawType
返回最外层<>前面那个类型,比如Map< K, V>返回Map。
getOwnerType
获得这个类型的所有者的类型,这一点可以参考在一个类或接口其内部定义接口或者类,外部类或接口的类型就是内部接口和类的所有者类型。比如参考如下:
//Map的源码
public interface Map<K, V> {
...
interface Entry<K, V> {
...
}
...
}
//Map.Entry的接口所有者就是Map
2.TypeVariable
类型变量,描述类型也就是泛型中的变量,表示泛指任意或相关一类类型,也就是说狭义上的泛型(泛指某一类类型),一般用大写字母作为变量,比如K、V、E等。
TypeVariable的源码如下:
public interface TypeVariable<D extends GenericDeclaration> extends Type {
//获得泛型的上限,若未明确声明上边界则默认为Object
Type[] getBounds();
//获取声明该类型变量实体(即获得类、方法或构造器名)
D getGenericDeclaration();
//获得名称,即K、V、E之类名称
String getName();
}
类型变量的定义,< E>,在E的前后加上尖括号,参考如下:
//1.在类class上定义类型变量
class A<T> {
T a;
}
//2.在方法上定义,方法上类型变量定义不是在参数里边,必须在返回值之前,static等修饰符后
public <E> void test(E e) {}
//3.定义在构造器上
public <K> A(K k) {}
注意:类型变量定义的时候不能定义下限(即不能有super),否则编译报错。T extends classA表示泛型有上限class A,因为在使用过程中能够保证传入的参数拥有class A的方法和属性,但是T super class A就不能确定传入的参数和方法了。
类型变量所具有的方法
getBounds
获得该类型变量的上限,也就是泛型中extend右边的值,例如List< T extends Number>,Number就是类型变量T的上限;如果只是简单的定义了List< T>,没有显示的定义extends,则默认的上限是Object。参考如下范例:
//没有定义extends的情况下
public class TypeVariableTest<T> {
private T list = null;
public static void main(String[] args) {
try {
Field field = TypeVariableTest.class.getDeclaredField("list");
Type type = field.getGenericType();
if (type instanceof TypeVariable) {
TypeVariable tv = (TypeVariable) type;
Type[] types = tv.getBounds();
for (Type t : types) {
System.out.println(t);//结果输出 class java.lang.Object
}
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
}
//在显示定义extends的情况下
public class ParameterizedTest<T extends Number & Serializable & Comparable> {
private T t;
public static void main(String[] args) {
try {
Field field = ParameterizedTest.class.getDeclaredField("t");
Type type = field.getGenericType();
if (type instanceof TypeVariable) {
TypeVariable tType = (TypeVariable) type;
Type[] types = tType.getBounds();
for (Type t : types) {
System.out.println(t);//结果输出class java.lang.Number interface java.io.Serializable interface java.lang.Comparable
}
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
}
getGenericDeclaration
获取声明该类型变量实体(Class,Constructor,Method)
public class ParameterizedTest<T> {
private T t;
public static void main(String[] args) {
try {
Field field = ParameterizedTest.class.getDeclaredField("t");
Type type = field.getGenericType();
if (type instanceof TypeVariable) {
TypeVariable tType = (TypeVariable) type;
GenericDeclaration genericDeclaration = tType.getGenericDeclaration();
System.out.println(genericDeclaration);//结果输出 class com.king.testreflect.ParameterizedTest
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
}
getName
获取类型变量在源码中定义的名称。
public class ParameterizedTest<T> {
private T t;
public static void main(String[] args) {
try {
Field field = ParameterizedTest.class.getDeclaredField("t");
Type type = field.getGenericType();
if (type instanceof TypeVariable) {
TypeVariable tType = (TypeVariable) type;
String name = tType.getName();
System.out.println(name);//结果输出 T
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
}
3.GenericArrayType
泛型数组类型,表示上面两种类型的数组,描述的形式如:A< T>[]或T[]。
源码如下:
public interface GenericArrayType extends Type {
//获得这个数组元素类型,即获得:A<T>(A<T>[])或T(T[])
Type getGenericComponentType();
}
方法注意:无论从左向右存在几个[]并列,这个方法仅仅会脱去最右边[]之后剩下的内容充当这个方法的返回值。参考如下:
classA<K>[][] key;
Type type = Main.class.getDeclaredField("key").getGenericType(); System.out.println(((GenericArrayType)type).getGenericComponentType());
//输出结果
//com.fcc.test.classA<K>[]
4.WildcardType
通配符表达式,或泛型表达式,他虽然是Type的一个子接口,但并不是Java类型中的一种,表示的仅仅形如 ? extends T,? super K这样的通配符表达式。源码参考如下:
public interface WildcardType extends Type {
//获得泛型表达式上界(上限)
Type[] getUpperBounds();
//获得泛型表达式下界(下限)
Type[] getLowerBounds();
}
getUpperBounds
获取泛型表达式上届,根据API的注释提示:现阶段通配符表达式仅仅接受一个上边界或者下边界,这个和定义类型变量时候可以指定多个上边界是不一样。但是API为了保持扩展性,这里返回值为数组形式。
getLowerBounds
获取泛型表达式下界。
参考代码如下:
public <T> void test(List<? extends classA > a){}
Method method = Main.class.getMethod("test",List.class);
Type[] upperBounds = null;
Type[] lowerBounds = null;
Type[] types = method.getGenericParameterTypes();
for(Type type : types){
Type[] actualTypeArgument = ((ParameterizedType)type).getActualTypeArguments();
for(Type t : actualTypeArgument){
WildcardType wildcardType = (WildcardType) t;
lowerBounds = wildcardType.getLowerBounds();
upperBounds = wildcardType.getUpperBounds();
System.out.println("通配符表达式类型是:"+ wildcardType);
if(upperBounds.length != 0){
System.out.println("表达式上边界:"+Arrays.asList(upperBounds));
}
if(lowerBounds.length != 0){
System.out.println("表达式下边界:"+Arrays.asList(lowerBounds));
}
}
}
//输出结果
通配符表达式类型是:? extends com.fcc.test.classA
表达式上边界:[class com.fcc.test.classA]
参考博客
https://blog.csdn.net/kingdam578/article/details/78656626
https://blog.csdn.net/gdutxiaoxu/article/details/68926515
https://blog.csdn.net/a327369238/article/details/52621043