在代码中经常会看到这样的函数
public static void printColl(ArrayList<?> al){
Iterator<?> it = al.iterator();
while(it.hasNext())
{
System.out.println(it.next().toString());
}
}
常用的 T,E,K,V,?
本质上这些个都是通配符,没啥区别,只不过是编码时的一种约定俗成的东西。比如上述代码中的 T ,我们可以换成 A-Z 之间的任何一个 字母都可以,并不会影响程序的正常运行,但是如果换成其他的字母代替 T ,在可读性上可能会弱一些。通常情况下,T,E,K,V,? 是这样约定的:
- ? 表示不确定的 java 类型
- T (type) 表示具体的一个java类型
- K V (key value) 分别代表java键值中的Key Value
- E (element) 代表Element
那么?和具体字母的区别是什么呢
// 通过 T 来 确保 泛型参数的一致性
public <T extends Number> void
test(List<T> dest, List<T> src)
//通配符是 不确定的,所以这个方法不能保证两个 List 具有相同的元素类型
public void test(List<? extends Number> dest, List<? extends Number> src)
? 无界通配符
对于不确定或者不关心实际要操作的类型,可以使用无限制通配符(尖括号里一个问号,即 <?> ),表示可以持有任何类型
上界通配符 < ? extends E>
在类型参数中使用 extends 表示这个泛型中的参数必须是 E 或者 E 的子类,这样有两个好处:
- 如果传入的类型不是 E 或者 E 的子类,编译不成功
- 泛型中可以使用 E 的方法,要不然还得强转成 E 才能使用
下界通配符 < ? super E>
用 super 进行声明,表示参数化的类型可能是所指定的类型,或者是此类型的父类型,直至 Object
下面是例子
public class FanXing {
TestA a = new TestA("13");
TestA b = new TestA(123);
public void getClass1(TestA<?> test) {
}
//报错
public void getClass2(TestA<T> test) {
}
}
class TestA<T> {
private T t;
public TestA(T key) {
this.t = key;
}
}
在使用泛型作为方法的参数时 就需要使用泛型通配符来解除传入参数的类型,类型参数就做不到
<?>与<字母>的还有一个区别就在于 字母形参可以在之后的函数调用 T t= it.next();
public static void printColl(ArrayList<T> al){
Iterator<T> it = al.iterator();
while(it.hasNext())
{
T t = it.next();
System.out.println(t.toString());
}
}