当前位置: 移动技术网 > IT编程>开发语言>Java > 谈谈Java类型中ParameterizedType,GenericArrayType,TypeVariabl,WildcardType

谈谈Java类型中ParameterizedType,GenericArrayType,TypeVariabl,WildcardType

2019年07月22日  | 移动技术网IT编程  | 我要评论

(1). 和反射+泛型有关的接口类型

java.lang.reflect.type:java语言中所有类型的公共父接口
java.lang.reflect.parameterizedtype
java.lang.reflect.genericarraytype
java.lang.reflect.wildcardtype

1. type直接子接口

parameterizedtype,genericarraytype,typevariable和wildcardtype四种类型的接口

parameterizedtype: 表示一种参数化的类型,比如collection
genericarraytype: 表示一种元素类型是参数化类型或者类型变量的数组类型
typevariable: 是各种类型变量的公共父接口
wildcardtype: 代表一种通配符类型表达式,比如?, ? extends number, ? super integer【wildcard是一个单词:就是“通配符”】

2. type直接实现子类 :class类

3. java.lang.reflect.type接口

type所有类型指代的有:原始类型 (raw types)【对应class】,参数化类型 (parameterizedtypes)【对应parameterizedtype】, 数组类型 (array types)【对应genericarraytype】,类型变量 (type variables)【对应typevariable】,基本数据类型(primitivetypes)【仍然对应class】

4. java.lang.reflect.parameterizedtype接口

parameterizedtype接口类型的含义

表示参数化类型。比如:map这种参数化类型

获取参数化类型<>中的实际类型

源码声明:type[] getactualtypearguments();

【注意】无论<>中有几层<>嵌套,这个方法仅仅脱去最外层的<>之后剩下的内容就作为这个方法的返回值。

public static  e methodiv( 
arraylist> al1, 
arraylist al2, 
arraylist al3, 
arraylistextends number> al4, 
arraylist al5){}

那么他的每一参数总体上看都是参数化类型的。

{1}. 对于arraylist>,通过getactualtypearguments()返回之后,脱去最外层的<>之后,剩余的类型是arraylist。因此对这个参数的返回类型是parameterizedtype。

{2}. 对于arraylist,通过getactualtypearguments()返回之后,脱去最外层的<>之后,剩余的类型是e。因此对这个参数的返回类型是typevariable。

{3}. 对于arraylist,通过getactualtypearguments()返回之后,脱去最外层的<>之后,剩余的类型是string。因此对这个参数的返回类型是class。

{4}. 对于arraylistextends number>,通过getactualtypearguments()返回之后,脱去最外层的<>之后,剩余的类型是? extendsnumber。因此对这个参数的返回类型是wildcardtype。

{5}. 对于arraylist,通过getactualtypearguments()返回之后,脱去最外层的<>之后,剩余的类型是e[]。因此对这个参数的返回类型是genericarraytype。

所以,可能获得各种各样类型的实际参数,所以为了统一,采用直接父类数组type[]进行接收。

4. java.lang.reflect. genericarraytype接口

genericarraytype接口类型的含义

表示泛型数组类型。比如:void method(arraylist[] al){…}

【注意】<>不能出现在数组的初始化中,即new数组之后不能出现<>,否则javac无法通过。但是作为引用变量或者方法的某个参数是完全可以的。

获取泛型数组中元素的类型

源码声明:type getgenericcomponenttype();

【注意】无论从左向右有几个[]并列,这个方法仅仅脱去最右边的[]之后剩下的内容就作为这个方法的返回值。

为什么返回值类型是type?

public static e methodv(
string[] p1,
e[] p2,
arraylist[] p3,
e[][] p4){}

{1}. 对于string[],通过getcomponenttype()返回之后,脱去最右边的[]之后,剩余的类型是string。因此对这个参数的返回类型是class

{2}. 对于e[],通过getcomponenttype()返回之后,脱去最右边的[]之后,剩余的类型是e。因此对这个参数的返回类型是typevariable

{3}. 对于arraylist[],通过getcomponenttype()返回之后,脱去最右边的[]之后,剩余的类型是arraylist。因此对这个参数的返回类型是parameterizedtype

{4}. 对于e[][],通过getcomponenttype()返回之后,脱去最右边的[]之后,剩余的类型是e[]。因此对这个参数的返回类型是genericarraytype

5. java.lang.reflect. genericarraytype接口

typevariable接口类型的含义

表示类型参数或者又叫做类型变量。比如:void method(e e){}中的e就是类型变量

获取类型变量的泛型限定的上边界的类型

源码声明:type[] getactualtypearguments();

【注意】这里面仅仅是上边界。原因就是类型变量在定义的时候只能使用extends进行(多)边界限定。不能使用super,否则编译无法通过。同时extends给出的都是类型变量的上边界。

为什么是返回类型是数组?因为类型变量可以通过&进行多个上边界限定,因此上边界有多个,因此返回值类型是数组类型[ ]。

例如下面的方法:

public static extends map& cloneable&serializable> e methodvi(e e){…}

e的第一个上边界是map,是parameterizedtype类型

e的第二个上边界是cloneable,是class类型

因此,为统一,返回值的数组的元素类型就是type

6. java.lang.reflect.wildcardtype接口

wildcardtype接口类型的含义

表示通配符类型的表达式。

比如 void printcoll(arraylistal); 中的 ? extends number

【注意】根据上面api的注释提示:现阶段通配符表达式仅仅接受一个上边界或者下边界,这个和定义类型变量时候可以指定多个上边界是不一样。但是api说了,为了保持扩展性,这里返回值类型写成了数组形式。实际上现在返回的数组的大小就是1

获取通配符表达式对象的泛型限定的上边界的类型

源码声明:type[] getupperbounds();

【注意】上面说了,现阶段返回的type[ ]中的数组大小就是1个。写成type[ ]是为了语言的升级而进行的扩展。

例如下面的方法:

{1}. public static voidprintcoll(arraylistextends arraylist> al){}

通配符表达式是:? extendsarraylist,这样 extends后面是?的上边界,这个上边界是parameterizedtype类型。

{2}. public static  voidprintcoll(arraylistextends e> al){}

通配符表达式是:? extends e,这样 extends后面是?的上边界,这个上边界是typevariable类型

{3}.public static  voidprintcoll(arraylistextends e[]> al){}

通配符表达式是:? extends e[],这样 extends后面是?的上边界,这个上边界是genericarraytype类型

{4}.public static  voidprintcoll(arraylistextends number> al){}

通配符表达式是:? extends number,这样 extends后面是?的上边界,这个上边界是class类型

最终统一成type作为数组的元素类型。

7. type及其子接口的来历

一. 泛型出现之前的类型

没有泛型的时候,只有所谓的原始类型。此时,所有的原始类型都通过字节码文件类class类进行抽象。class类的一个具体对象就代表一个指定的原始类型。

二. 泛型出现之后的类型

泛型出现之后,扩充了数据类型。从只有原始类型扩充了参数化类型、类型变量类型、泛型限定的的参数化类型 (含通配符+通配符限定表达式)、泛型数组类型。

三. 与泛型有关的类型不能和原始类型统一到class的原因

[1]. 【产生泛型擦除的原因】

本来新产生的类型+原始类型都应该统一成各自的字节码文件类型对象。但是由于泛型不是最初java中的成分。如果真的加入了泛型,涉及到jvm指令集的修改,这是非常致命的。

[2]. 【java中如何引入泛型】

为了使用泛型的优势又不真正引入泛型,java采用泛型擦除的机制来引入泛型。java中的泛型仅仅是给编译器javac使用的,确保数据的安全性和免去强制类型转换的麻烦。但是,一旦编译完成,所有的和泛型有关的类型全部擦除。

[3]. 【class不能表达与泛型有关的类型】

因此,与泛型有关的参数化类型、类型变量类型、泛型限定的的参数化类型 (含通配符+通配符限定表达式)、泛型数组类型这些类型全部被打回原形,在字节码文件中全部都是泛型被擦除后的原始类型,并不存在和自身类型一致的字节码文件。所以和泛型相关的新扩充进来的类型不能被统一到class类中。

(4). 与泛型有关的类型在java中的表示

为了通过反射操作这些类型以迎合实际开发的需要,java就新增了parameterizedtype,genericarraytype,typevariable 和wildcardtype几种类型来代表不能被归一到class类中的类型但是又和原始类型齐名的类型。

(5). type的引入:统一与泛型有关的类型和原始类型class

【引入type的原因】

为了程序的扩展性,最终引入了type接口作为class,parameterizedtype,genericarraytype,typevariable和wildcardtype这几种类型的总的父接口。这样实现了type类型参数接受以上五种子类的实参或者返回值类型就是type类型的参数。

【type接口中没有方法的原因】

从上面看到,type的出现仅仅起到了通过多态来达到程序扩展性提高的作用,没有其他的作用。因此type接口的源码中没有任何方法。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网