JAVA泛型整理
本文于 1813 天之前发表,文中内容可能已经过时。
JAVA泛型整理
[TOC]
概述
泛型的本质是参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)
操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类
、泛型接口
、泛型方法
。
特性
1 | List<String> stringArrayList = new ArrayList<String>(); |
输出结果:D/泛型测试: 类型相同
。
通过上面的例子可以证明,在编译之后程序会采取去泛型化的措施。也就是说Java中的泛型,只在编译阶段有效。在编译过程中,正确检验泛型结果后,会将泛型的相关信息擦出,并且在对象进入和离开方法的边界处添加类型检查和类型转换的方法。也就是说,泛型信息不会进入到运行时阶段。
对此总结成一句话:泛型类型在逻辑上可以看成是多个不同的类型,实际上都是相同的基本类型。
类型与区别
?
表示不确定的java类型,是类通配符,代表所有类型。?不会进行类型推断T
(type)表示具体的一个java类型K V
(key value)分别代表java键值中的Key ValueE
(element)代表ElementN
(number)代表数值类型
- List<?
extends
T>和List <?super
T>有什么区别?
- List<? extends T>可以接受任何继承自T的类型的List
- List<? super T>可以接受任何T的父类构成的List
- 例如List<? extends Number>可以接受List
或List
Object
和T
的区别? Object是一个实打实的类,并没有泛指谁,只有指定的Object类的,而T可以泛指Object,指任何java类 型,范围更广
- 泛型的类型只能是类类型,不能是简单类型(简单八大数据类型)
如果有泛型方法和非泛型方法,都满足条件,会执行非泛型方法
泛型类
1 | class 类名称 <泛型标识:可以随便写任意标识号,标识指定的泛型的类型>{ |
1 | //此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型 |
泛型接口
1 | //定义一个泛型接口 |
泛型方法
1 | /** |
这不是
一个泛型方法,这也是一个普通的方法,只不过使用了泛型通配符?
1 |
|
泛型类的中的泛型方法
1 | class GenerateTest<T>{ |
泛型方法和可变参数
1 | public <T> void printMsg( T... args){ |
1 | printMsg("111",222,"aaaa","2323.4",55.55); |
静态方法与泛型
1 | public class StaticGenerator<T> { |
无论何时,如果你能做到,你就该尽量使用泛型方法。也就是说,如果使用泛型方法将整个类泛型化,
那么就应该使用泛型方法。另外对于一个static的方法而已,无法访问泛型类型的参数。
所以如果static方法要使用泛型能力,就必须使其成为泛型方法。
Sun的文档
1 | List<String>[] lsa = new List<String>[10]; // Not really allowed. |
这种情况下,由于JVM泛型的擦除机制,在运行时JVM是不知道泛型信息的,所以可以给oa[1]赋上一个ArrayList而不会出现异常,
但是在取出数据的时候却要做一次类型转换,所以就会出现ClassCastException,如果可以进行泛型数组的声明,
上面说的这种情况在编译期将不会出现任何的警告和错误,只有在运行时才会出错。
而对泛型数组的声明进行限制,对于这样的情况,可以在编译期提示代码有类型安全问题,比没有任何提示要强很多。
编译器
:把源码交给编译器编译成计算机可以执行的文件的过程(把java代码编成class文件的过程,编译期只是做一些翻译的功能,并没有把代码放在内存中运行起来,而只是)
运行期
:把编译后的文件交给计算机执行
以下是ok的
1 | List<?>[] lsa = new List<?>[10]; // OK, array of unbounded wildcard type. |
泛型通配符
形参
和实参
的区别
- 形参是形式参数,接收调用者传递的参数
- 实参是实体参数,调用时传递出的参数
T
和
?`的区别?
T
主要用于声明
泛型类或泛型方法?
主要用于使用
泛型类或泛型方法T
在同一个地方就代表一个具体的类型,而?
就代表所有类型,可以理解为所有类型的父类