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

(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接口的源码中没有任何方法。

(0)

相关推荐

  • 使用Java代码将IP地址转换为int类型的方法

    基本知识点    IP --> 整数: 把IP地址转化为字节数组 通过左移位(<<).与(&).或(|)这些操作转为int 整数 --> IP: 将整数值进行右移位操作(>>>),右移24位,再进行与操作符(&)0xFF,得到的数字即为第一段IP. 将整数值进行右移位操作(>>>),右移16位,再进行与操作符(&)0xFF,得到的数字即为第二段IP. 将整数值进行右移位操作(>>>),右移8位,再进行与操

  • JavaScript判断FileUpload控件上传文件类型

    为了代码变得更加简捷,笔者使用了正则表达式来获取文件扩展名,如果读者对正则表达式不太了解或者从来没有接触过,请马上恶补一下吧!毕竟它非常重要,大多数的编程语言都支持正则表达式. 大家都知道,后台获取FileUpload扩展名方法: string ext = Path.GetExtension(fu.PostedFile.FileName); JS判断FileUpload控件上传文件的扩展名: <html xmlns="http://www.w3.org/1999/xhtml"&g

  • JAVA中string数据类型转换详解

    在JAVA中string是final类,提供字符串不可以修改,string类型在项目中经常使用,下面给大家介绍比较常用的string数据类型转换: String数据类型转换成long.int.double.float.boolean.char等七种数据类型 复制代码 代码如下: * 数据类型转换 * @author Administrator * */ public class 数据类型转换 { public static void main(String[] args) { String c=

  • 简单谈谈javascript Date类型

    1 创建一个新的日期对象,如果不带参数,则对象自动获得当前的日期和时间 var d = new Date() 2 如果需要指定特定的日期,则可以通过Date.parse() 或者 Date().UTC(),返回时间戳作为 new Date()的参数 Date.parse() 用法: var time = Date.parse('2015/05/20'); var newDate = new Date(time);//Wed May 20 2015 00:00:00 GMT+0800 (中国标准时

  • java获取网络类型的方法

    本文实例讲述了java获取网络类型的方法.分享给大家供大家参考.具体如下: /**** * 获取网络类型 * * @param context * @return */ public static String getNetType(Context context) { try { ConnectivityManager connectMgr = (ConnectivityManager) context .getSystemService(Context.CONNECTIVITY_SERVIC

  • JavaScript数据类型判定的总结笔记

    用typeof 来检测数据类型 Javascript自带两套类型:基本数据类型(undefined,string,null,boolean,function,object)和对象类型. 但是如果尝试用typeof 来检测对象类型都一律返回"object"并不能加以区分 typeof null // "object" typeof [] // "object" typeof document.childNodes //"object&qu

  • JavaScript基本数据类型及值类型和引用类型

    在JavaScript中四种基本的数据类型:数值(整数和实数).字符串型(用""号或''括起来的字符或数值).布尔型(使True或False表示)和空值.在JavaScript的基本类型中的数据可以是常量,也可以变量.由于JavaScript采用弱类型的形式,因而一个数据的变量或常量不必首先作声明,而是在使用或赋值时确定其数据的类型的.当然也可以先声明该数据的类型,它是通过在赋值时自动说明其数据类型的. javascript中的变量 javascript中的变量只是一个占位符,前言已经

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

    (1). 和反射+泛型有关的接口类型 java.lang.reflect.Type:java语言中所有类型的公共父接口 java.lang.reflect.ParameterizedType java.lang.reflect.GenericArrayType java.lang.reflect.WildcardType 1. Type直接子接口 ParameterizedType,GenericArrayType,TypeVariable和WildcardType四种类型的接口 Paramet

  • 简单谈谈Java中String类型的参数传递问题

    提要:本文从实现原理的角度上阐述和剖析了:在Java语言中,以 String 作为类型的变量在作为方法参数时所表现出的"非对象"的特性. 一.最开始的示例 写代码最重要的就是实践,不经过反复试验而得出的说辞只能说是凭空遐想罢了.所以,在本文中首先以一个简单示例来抛出核心话题: public class StringAsParamOfMethodDemo { public static void main(String[] args) { StringAsParamOfMethodDem

  • 简单谈谈Java中的方法和方法重载

    今天我们就讲一点内容,来说说Java中的方法和方法重载以及需要注意的一些地方: 方法: Java的方法类似与其他语言的函数,是一段用来完成特定功能的代码片段, 声明格式: [修饰符1 修饰符2 ....] ,返回值类型 方法名 (形式参数列表) { Java语句: - - -} 形式参数:在方法被调用时用于接受外界输入的数据: 实参: 调用方法时世界传给方法的数据: 返回值: 方法在执行完毕后返回给调用他的环境的数据: 返回值类型: 事先约定好的返回值的数据类型,如无返回值必须给出返回值类型vo

  • 谈谈Java中自定义注解及使用场景

    Java自定义注解一般使用场景为:自定义注解+拦截器或者AOP,使用自定义注解来自己设计框架,使得代码看起来非常优雅.本文将先从自定义注解的基础概念说起,然后开始实战,写小段代码实现自定义注解+拦截器,自定义注解+AOP. 一. 什么是注解(Annotation) Java注解是什么,以下是引用自维基百科的内容 Java注解又称Java标注,是JDK5.0版本开始支持加入源代码的特殊语法元数据. Java语言中的类.方法.变量.参数和包等都可以被标注.和Javadoc不同,Java标注可以通过反

  • 详解Java泛型中类型擦除问题的解决方法

    以前就了解过Java泛型的实现是不完整的,最近在做一些代码重构的时候遇到一些Java泛型类型擦除的问题,简单的来说,Java泛型中所指定的类型在编译时会将其去除,因此List 和 List 在编译成字节码的时候实际上是一样的.因此java泛型只能做到编译期检查的功能,运行期间就不能保证类型安全.我最近遇到的一个问题如下: 假设有两个bean类 /** Test. */ @Data @NoArgsConstructor @AllArgsConstructor public static class

  • 简单谈谈java中final,finally,finalize的区别

    (1) final:修饰符(关键字),如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承.因此一个类不能既被声明为 abstract的,又被声明为final的.将变量或方法声明为final,可以保证它们在使用中不被改变.被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改.被声明为final的方法也同样只能使用,不能重载 (2) finally:在异常处理时提供 finally 块来执行任何清除操作.如果抛出一个异常,那么相匹配的 catc

  • 浅析java中String类型中“==”与“equal”的区别

    一.前言 1.1.首先很多人都知道,String中用"=="比较的是地址,用equals比较的是内容,很多人对此用的是记忆法,通过记忆来加强此的引用,但是其真正的原理其实并不难,当我们真正明白其为什么的时候,用起来也会更加灵活,更加有底气(形容得不太好,朋友别见怪): 二相关知识的准备 类型常量池 运行时常量池 字符串常量池 我们今天讨论的主题是当然是字符串常量池: 为什么在这要把另外两个常量池拿出说一下呢,首先小生我在网上或者cnds上看到很多人在争论字符串常量池是存在与方法区还是堆

  • 谈谈Java中的守护线程与普通线程

    守护线程与普通线程的唯一区别是:当JVM中所有的线程都是守护线程的时候,JVM就可以退出了:如果还有一个或以上的非守护线程则不会退出.(以上是针对正常退出,调用System.exit则必定会退出) 所以setDeamon(true)的唯一意义就是告诉JVM不需要等待它退出,让JVM喜欢什么退出就退出吧,不用管它. 守护线程在没有用户线程可服务时自动离开,在Java中比较特殊的线程是被称为守护(Daemon)线程的低级别线程.这个线程具有最低的优先级,用于为系统中的其它对象和线程提供服务.将一个用

  • java数组中的异常类型整理

    对于程序中出现异常,是很多程序员不想看到的情况,因为这就需要我们去查询异常的原因,然后进行一些处理异常的操作.在Java数组操作时,也会有一些异常情况的发生.这里我们罗列出了两种:ClassCastException和NullPointerException,下面我们来看一下具体的介绍. 1.异常种类 检查型异常和非检查型异常的主要区别在于其处理方式.检查型异常都需要使用try,catch 和finally 关键字在编译器进行处理,否则会出现编译器报错.对于非检查型异常则不需要这样做.Java中

  • 详细谈谈Java中long和double的原子性

    目录 前言 JVM中对long的操作是不是原子操作? 为什么对long的操作不是原子的? 在硬件,操作系统,JVM都是64位的情况下呢? 总结 前言 java中基本类型中,long和double的长度都是8个字节,32位(4字节)处理器对其读写操作无法一次完成,那么,JVM,long和double是原子性的吗? JVM中对long的操作是不是原子操作? 首先,通过一段程序对long的原子性进行判断.测试程序如下: public class LongAtomTest implements Runn

随机推荐