泛型是jdk5中引入的一个新特性,泛型提供了编译时的类型安全检查机制,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数,泛型不存在于Java虚拟机中,java泛型是一个伪泛型。
通用的泛型类定义格式如下:
class name
其中T1,T2..是类型参数,类型参数既可以有一个或者有多个。下面使用一个具体的例子来使用泛型类,该类中的泛型参数可以任意指定非基本类型(任何类类型,任何接口类类型,任何数组类型,甚至是另一个类型变量)
/** * Generic version of the Box class.
* @param the type of the value being boxed
*/
public class Box {
// T stands for "Type"
private T t;
public void set(T t) {
this.t = t;
}
public T get() {
return t;
}
}
在上面的Box类中有open()是一个泛型方法,注意这get和set这2个方法的类型参数依赖于Box类的类型参数,Box类的类型参数定义什么类型,那么这2个方法的类型参数就是啥,比如new Box(String) 定义的类型参数是String,那么get和set方法中的参数类型就是String,这get和set方法不是泛型方法.只有open()是泛型方法,识别泛型方法很简单就看方法前面有没有
/**
* 普通的方法,原因这个是泛型类在实例化时指定了泛型类的具体类型,他只是一个普通的方法,下面的
* get()方法也是同理
*/
public void setT(T t) {
this.t = t;
}
/**
* 普通的泛型方法
*/
public T getT() {
return t;
}
/**
* 普通的泛型方法
*/
public void open(T t){
}
下面我们实例化一下参数化类型(指定了泛型的类型参数):
public static void main(String[] args) {
Box box = new Box<>();
box.setT("这是一个String类型的类型方法实参");
// int i = box.getT(); //编译器报错,返回的getT返回类型是String,但是我们用了int类型去接收,编译不通过
String t = box.getT();
System.out.println(t);
}
打印结果
注意此时的open方法中参数的泛型参数T和 和 Box类的泛型T不是同一个泛型变量,原因在于open方法中指定了一个新的泛型参数T。我们同样使用上面box实例去调用open方法,并且同样的调用set方法做一个对比
通过编译器的代码提示我们看到,set方法中提示我们传入的参数类型指定的是String,而open方法提示的参数类型还是为指定的类型参数,得出结论,open泛型方法中的类型参数T和Box类中的类型参数不是同一个类型,open类型方法的类型参数根据传入的实参的实际类型来的。而set和get种的T 是参数化类型指定的类型,get和set只是普通的方法,而不是泛型方法。
public interface IBox {
void pack(T t);
}
在通用代码中,称为通配符的问号( ? )表示未知类型。通配符可以在多种情况下使用:作为参数,字 段或局部变量的类型;有时作为返回类型(尽管更具体的做法是更好的编程习惯)。通配符从不用作泛 型方法调用,泛型类实例创建或超类型的类型参数。
上界通配符就是将未知类型限定为特定类型或者该类型的子类型。上界通配符只能读不能存
上界通配符使用 ? 后跟extends 关键字,假设你要编写一适用于List 或者List的方法,可以使用上限通配符来实现。
下面看这个Test类中有个static方法process,
public class Test {
public static void main(String[] args) {
List list = new ArrayList<>();
for (int i = 0; i <3 ; i++) {
list.add(i);
}
process(list);
}
static void process(List extends Number> list){
for (int i: list) {
System.out.println(i);
}
}
}
运行结果:
从上面可以看到 process方法里面的参数是使用了上限通配符 ,而我们调用的该方法传入的list的类型参数确是却是Number的子类Integer。上限通配符的作用就是放宽了对变量的限制。
但是使用了上限通配之后,List只能读不能写如下:
下界通配符就是将位置类型限制为特定类型或者该类型的超类型。下界通配符只能存不能读
使用方式:? super 特定类型
下面的process_1方法中传递了一个list,使用了下届通配符
static void process_1(List super Integer> list){
for (int i = 0; i <3 ; i++) {
list.add(new Integer(i));
}
System.out.println(list.size());
}
调用该方法结果:
看到为list中添加了3个Integer对象,数组的长度为3.,现在读取list中的对象,
读取方法报错,由此可见使用了下界通配符的的list只能存不能读。
无界通配符类型使用通配符> 来指定,例如List>这就是所谓的未知类型的列表,有2种情况下,无界通配符是一种有用的方法。
1、如果你正在编写一个可以使用object类中国提供的功能和方法。
2、当代码使用通用类总不依赖于类型参数的方法时。例如list.size,list.clear。
考虑下面的printList方法
public static void printList(List
printList 的目标是打印任何类型的列表,但是它无法实现这个目标 - 它仅打印一个 Object 实例列表; 它不能打印 List
、List
、List
等,因为它们不是 List
的子类型。 要写一个通用的 printList 方法,使用 List >
public static void printList(List> list) {
for (Object elem: list)
System.out.print(elem + " ");
System.out.println();
}
因为对于任何具体类型 A,List
是 List >
的子类型,所以可以使用 printList 打印任何类型的列表:
List li = Arrays.asList(1, 2, 3);
List ls = Arrays.asList("one", "two", "three");
printList(li);
printList(ls);
类型安全,编译器在代码开发阶段就能够进行类型的验证
消除强制类型的转换,消除代码种的强制类型转换,代码可读性更高
提高方法的复用性,