首先得明确通配符与类型参数都是泛型,泛型其实就是参数化类型。比如:list<Integer>,其中Integer就是具体的类型,表名了list里面只能放Integer类型的数据,list<Object> Object就表示list里面只能放Object类型。list<T> T尽管我们不知道是什么类型,但是不代表它可以是任意类容,只是我们不了解具体限制是什么,但是它有限制,只有在运行时才知道。
那我们就会想到list<Object>与list<T>到底有什么区别呢。用一个例子来说明:
list<Object> list = new ArrayList<Student>;这样是不允许的,但是list<T> list = new ArrayList<Student>;这样就是允许的。
通配符是什么?
在java中通配符其实就是带有 ? 的一个表达式,可想而知?就表示的是未知的类型。比如:list< ?>,list<? extends T>等。
泛型与通配符到底有什么用?
在没有使用泛型的时候,我们常常会使用强制转换,就发生java.lang.ClassCastException异常。比如:
List list = new ArrayList();
list.add("abc");
list.add(123);
这个是完全允许的,但是当我们取出的时候也许就会忘记。
for(int i = 0;i<list.size();i++){
String name = (String)list.get(i);
}
这时在程序运行之前是不会报错的,而是在程序运行之后就会报ClassCastException。
而泛型的好处其实就在于在编译的时候检查类型安全,并且所有的的强制转换都是自动和隐式的。比如:
List<String> list = new ArrayList<String>();
list.add("abc");
list.add(123);-----编译器就会提示错误
通配符就是为了解决类型被限制死而不能动态根据实例来确定的缺点。比如:
List<String> strings = new ArraryList<String>();
strings.add("a");
List<Integer> intg = new ArraryList<Integer>();
intg .add(1);
这时想写一个方法输出strings和intg
public static void printfDate()------这里面的参数填List<String>,List<Integer>肯定都是不行的,所以就出现了通配符
public static void printfDate(List<?> list){
System.out.println("list = " + list.get(0));
}
此外,通配符还分为限制的通配符,有通配符上限,即使用extends,通配符下限,及使用super。在这里为了便于记住使用哪种通配符类型:
PECS 表示 producer-extends, consumer-super。即如果参数化类型表示一个T生产者,就使用<? extends T>。表示一个T消费者,就使用<? super T>。比如:
public static <T extends Comparable<? super T>> T max(List<? extends T> list){
}