Java学习笔记#06 泛型中类型参数T和通配符?的区别

区别1
对于Collection<T>编译器会将T推断为传入的具体类型,而对于Collection<?>编译器会把?推断为未知类型,此时调用add(new Object())方法编译无法通过,因为add()方法接收的参数应为未知类型的子类,而未知类型到底是什么类型没法知道,所以不能传入任何对象,唯一的例外是null,因为null可以是任意类型。

Collection<?> c = new ArrayList<String>();
c.add(new Object()); // 编译报错
c.add(null);

区别2
另一方面,对于Collection<?>可以调用get()方法,尽管不知道返回值类型,但无论如何都可以将其赋给一个Object变量。
考虑打印一个列表的两种写法:

public static void printL(List<?> list){
	for (Object o : list) {
    	System.out.println(o);
	}
}

public static <T> void printL2(List<T> list){
	for (T o : list) {
    	System.out.println(o);
	}
}

对于第二种的写法,留意到T在方法签名中只出现了一次,也就是说T没有用于表达任何实参类型、返回值类型和异常类型相互之间的依赖关系,如果不存在这种相互依赖的关系,使用泛型方法是一种糟糕的代码风格,应该使用通配符。而当存在这些依赖关系的时候,应该用类型参数T,不能通配符。
举一些例子:
Collection接口里的toArray方法使用了类型参数,反映参数a和返回值之间类型关系

<T> T[] toArray(T[] a);

而Collection接口里的addAll方法使用了通配符

boolean addAll(Collection<? extends E> c);

Comparator接口里的compare方法使用了类型参数,反映两个参数o1和o2之间的类型关系

int compare(T o1, T o2);

区别3
类型参数不能指定下界,而通配符可以用super指定下界

public class MyClass {
	class C {}
	// C是上界
	<T extends C> void genericMethod1(Collection<T> c){}
	// C是下界
	<T super C> void genericMethod2(Collection<T> c){} //编译报错
	// C是上界
	void genericMethod3(Collection<? extends C> c){}
	// C是下界
	void genericMethod4(Collection<? super C> c){}
}

区别4
类型参数的上界可以是一个类,也可以有多种边界(multiple bounds),即上界可以是一个类/接口后面跟多个接口构成的交集类型(intersection type),而通配符的上界只能是一个类

public class MyClass {
	class C {}
    interface I1 {}
    interface I2 {}
	<T extends C> void genericMethod5(Collection<T> c){}
	<T extends C & I1 & I2> void genericMethod6(Collection<T> c){}
	<T extends I1 & I2> void genericMethod7(Collection<T> c){}
	void genericMethod8(Collection<? extends C> c){}
	void genericMethod9(Collection<? extends C & I1 & I2> c){} //编译报错
}

区别5
类型参数可以用于泛型类的签名,通配符不可以

public class MyClass<T> {}
public class MyClass<?> {} //编译报错

区别6
类型参数可以声明变量,通配符不可以

public class MyClass<T> {
	T t;
	? t; //编译报错
	void myMethod1(E e){}
    void myMethod2(? e){} //编译报错
}

参考
https://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.10、
https://docs.oracle.com/javase/tutorial/java/generics/wildcards.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值