黑马程序员技术交流社区

标题: 分享一下学习泛型之后的总结 [打印本页]

作者: 乖睡觉咯    时间: 2013-8-29 00:07
标题: 分享一下学习泛型之后的总结
泛型总结

一,泛型概述
1.泛型是1.5的新特性,泛型是提供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入,编译器编译带类型说明的集合时会去除掉“类型”信息,使程序运行效率不受影响,对于参数化的泛型类型,getClass()方法的返回值和原始类型完全一样。由于编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器,就可以往某个泛型集合中加入其它类型的数据,例如,用反射得到集合,再调用其add方法即可。


二,泛型的基本运用

1.泛型一般跟集合结合使用,在集合后面加一个<>尖括号,在尖括号里面声明集合里面要存储的类型,这样子,声明之后,这个集合就只能存储尖括号里面声明的类型,其他类型在装进去之后,就会被报错!如 List<String> list =new ArrayList<String>();

2.泛型可以对集合里面的数据进行限定,避免数据存储的过于杂乱,在jdk1.5之后的版本,你也可以不用泛型,但是编译器会报告一个小小的安全警告!

三。泛型的内部原理

1.泛型只能保留在编译期,当程序被加载进内存转成字节码后,那个泛型标记就会被去除,这个就是泛型在运行过程中的去类型化,

2.由于泛型的去类型化,我们可以用反射的方法往已经限定好类型的集合装入其他类型的数据!实例如下:
        List<String> list =new ArrayList<String>();
            list.add("nihao");
            list.getClass().getMethod("add", Object.class).invoke(list, 11);
            System.out.println(list);

3.泛型术语
ArrayList<E>类定义和ArrayList<Integer>类引用中涉及如下术语:
整个称为ArrayList<E>泛型类型
ArrayList<E>中的E称为类型变量或类型参数
整个ArrayList<Integer>称为参数化的类型
ArrayList<Integer>中的Integer称为类型参数的实例或实际类型参数
ArrayList<Integer>中的<>念着typeof
ArrayList称为原始类型

4. 泛型的一些小知识点
1.参数化类型是可以引用原始类型的,编译器会通过但是有警告!原始类型也可以引用参数化类型!

2.参数化类型不考虑继承关系
Vector<Object> v = new Vector<String>(); //也错误!
Vector<String> v = new Vector<Object>(); //错误!///不写<Object>没错,写了就是明知故犯

3.数组不能引用泛型,泛型

四,泛型通配符

1.?通配符,表示是任意类型的参数,这个跟Object的泛型参数的区别是,Object可以传任意类型的东西进集合,但是你不能兼容参数化了其他类型的集合,而这个?号可以!
使用?通配符可以引用其他各种参数化的类型,?通配符定义的变量主要用作引用,可以调用与参数化无关的方法,不能调用与参数化有关的方法。

2.泛型?通配符的上下限定。
?后跟一个关键字 Extends 或者super关键字,再跟一个具体类型,就可以限定,你可以传这个关键字后面的那个类型的父类或者子类!
《?super 类型》,表示限定下限,你只能传那个类型,或者那个类型的父类。
《?extends 类型》,表示限定上限,你只能传那个类型,或者那个类型的子类!
《?extends U》,你可以同时指定类型跟类型的子类!反之一样

五,自定义泛型

1.泛型在应用在方法上,可以避免写多个重载方法,直接定义泛型就可以写个通用的方法!
在返回值之前<>用一对尖括号来说明,里面写个类型变量,可以是T也可以是其他类型!

2.1.Java中的泛型类型(或者泛型)类似于 C++ 中的模板。但是这种相似性仅限于表面,Java 语言中的泛型基本上完全是在编译器中实现,用于编译器执行类型检查和类型推断,然后生成普通的非泛型的字节码,这种实现技术称为擦除(erasure)(编译器使用泛型类型信息保证类型安全,然后在生成字节码之前将其清除)。这是因为扩展虚拟机指令集来支持泛型被认为是无法接受的,这会为 Java 厂商升级其 JVM 造成难以逾越的障碍。所以,java的泛型采用了可以完全在编译器中实现的擦除方法。
3.自定义泛型的类型推断,当你传了 两个不同类型的数值之后,那么你那个T,就会求他们两个类型的交集类型!

4. 只有引用类型才能作为泛型方法的实际参数,对于add方法,使用基本类型的数据进行测试没有问题,这是因为自动装箱和拆箱了。 swap(new int[3],3.5);语句会报告编译错误,这是因为编译器不会对new int[3]中的int自动拆箱和装箱了,因为new int[3]本身已经是对象了,你想要的有可能就是int数组呢?它装箱岂不弄巧成拙了。

5.在自定义方法中,也可以定义泛型变量类型的上下限!!还可以用&符号进行连接限定多个条件!
如<V extends Serializable & cloneable> void method(){}

6.构造方法 ,静态方法,普通方法,都可以使用泛型!

7.自定义泛型类

可以在类身上定义泛型,这样子,在类被创建的时候,类内部调用这个泛型的地方就全部被实体化!也可以在类内部任意引用该类型变量!
在对泛型类型进行参数化时,类型参数的实例必须是引用类型,不能是基本类型。
当一个变量被声明为泛型时,只能被实例变量、方法和内部类调用,而不能被静态变量和静态方法调用。因为静态成员是被所有参数化的类所共享的,所以静态成员不应该有类级别的类型参数

8.用反射获得类身上的实际类型参数
通过获得类的字节码,然后获得对应方法,在得到方法上面的形参, Typ[] getGenericParameterTypes()  得到TYPE类型的数组,数组里面的类型是 ParameterizedType类型的!ParameterizedType 的 Type getRawType() 就可以获取形参的名字Type[]getActualTypeArguments() 可以获得该泛型类型的实参上面的泛型类型!






作者: 许庭洲    时间: 2013-9-2 20:57
值得学习ing!




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2