java开发一些常识


Java类型中ParameterizedType,GenericArrayType,TypeVariabl,WildcardType详解

发表于 2014-10-08 11:34:084595次阅读| 来源 webkfa| 作者 小豆豆
摘要: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<arraylist> al1,  
  • ArrayList al2,  
  • ArrayList al3,  
  • ArrayListextends Number> al4,  
  • ArrayList al5){} 

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

    {1}. 对于ArrayList<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 <e extends Map& Cloneable&Serializable> E methodVI(E 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就新增了ParameterizedTypeGenericArrayTypeTypeVariable 和WildcardType几种类型来代表不能被归一到Class类中的类型但是又和原始类型齐名的类型

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

    引入Type的原因

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

    Type接口中没有方法的原因

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


我们为什么需要DTO(数据传输对象)

DTO即数据传输对象。之前不明白有些框架中为什么要专门定义DTO来绑定表现层中的数据,为什么不能直接用实体模型呢,有了DTO同时还要维护DTO与Model之间的映射关系,多麻烦。

然后看了这篇文章中的讨论部分才恍然大悟。

摘两个比较有意义的段落。

表现层与应用层之间是通过数据传输对象(DTO)进行交互的,数据传输对象是没有行为的POCO对象,它 的目的只是为了对领域对象进行数据封装,实现层与层之间的数据传递。为何不能直接将领域对象用于 数据传递?因为领域对象更注重领域,而DTO更注重数据。不仅如此,由于“富领域模型”的特点,这样 做会直接将领域对象的行为暴露给表现层。

需要了解的是,数据传输对象DTO本身并不是业务对象。数据传输对象是根据UI的需求进行设计的,而不 是根据领域对象进行设计的。比如,Customer领域对象可能会包含一些诸如FirstName, LastName, Email, Address等信息。但如果UI上不打算显示Address的信息,那么CustomerDTO中也无需包含这个 Address的数据

简单来说Model面向业务,我们是通过业务来定义Model的。而DTO是面向界面UI,是通过UI的需求来定义的。通过DTO我们实现了表现层与Model之间的解耦,表现层不引用Model,如果开发过程中我们的模型改变了,而界面没变,我们就只需要改Model而不需要去改表现层中的东西。


三个都是java实体对象,vo,跟po比较类似,po是persistent object,是在是orm框架中的entity,po的每个属性基本上都对应数据库表里面的某个字段,而vo(value object)有时可以跟po一样,有时并不对应。POJO(Plain Old Java Objects)是简单java对象,他并不继承任何类(继承Object),实现任何接口,只有属性跟get set方法。而po一般要实现序列化接口,有时也继承一些类。

Class<T>在实例化的时候,T要替换成具体类
Class<?>它是个通配泛型,?可以代表任何类型


  1.  //当前对象的直接超类的 Type  
  2.         Type genericSuperclass = getClass().getGenericSuperclass();  
  3.         if(genericSuperclass instanceof ParameterizedType){  
  4.             //参数化类型  
  5.             ParameterizedType parameterizedType= (ParameterizedType) genericSuperclass;  
  6.             //返回表示此类型实际类型参数的 Type 对象的数组  
  7.             Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();  
  8.             this.clazz= (Class<T>)actualTypeArguments[0];  
  9.         }else{  
  10.             this.clazz= (Class<T>)genericSuperclass;  

Object是基类,所有类的祖宗;
Type是类型,如基本数据类型;
Class是对象,每个类的对象的共性做的抽象。

Class实例化后就是对象,如类A,A.class就是class对象。



遇到<A>,<B>,<K,V>等,是用到了java中的泛型。 
一般使用<T>来声明类型持有者名称,自定义泛型类时,类持有者名称可以使用T(Type) 
如果是容器的元素可以使用E(Element),若键值匹配可以用K(Key)和V(Value)等, 
若是<?>,则是默认是允许Object及其下的子类,也就是java的所有对象了。
 

所以说,如果是字每A,B,C,D...定义的,就是泛型,这里T只是名字上的意义而已T---type,E----Element 
K----key, V----value 
如果是?定义的,就是普通的Object或者其子类 

举例说明: 
Set<T> 表示 集合里 是   T类的实例 
List<E> 表示  集合里 是  E类的实例 
List<?> 表示 集合里的对象类型不确定,未指定 
List 同 List<?> 是一样的。
 

泛型的作用:
 
1、用泛型: 
Java代码   收藏代码
  1. List<T> list=new ArrayList<T>();  
  2. T t=list.get(0);  

2、不用泛型: 
Java代码   收藏代码
  1. List  list=new ArrayList();  
  2. T t=(T)list.get(0);  

相信你已经看出: 
a、用泛型只是确定了集合内的元素的类型,但却是在编译时确定了元素的类型再取出来时已经不再需要强转, 
增强程序可读性,稳定性和效率 
b、不用泛型时,如果是装入集合操作,那么元素都被当做Object对待,失去自己的类型,那么从集合中取出来时, 
往往需要转型,效率低,容易产生错误
 


方法一:直接强制转换。如:String  str= (String)123;
方法二:直接通过空字符串+数字的形式转换为字符串(前后都可以用)。如:String str= ""+123;
方法三:直接通过包装类来实现。如:String  str = String.valueOf(1231);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值