通配符基本使用
泛型的通配符:不知道使用什么类型来接收的时候,此时可以使用?,?表示未知通配符。
当使用泛型类或者接口时,传递的数据中,泛型类型不确定,可以通过通配符<?>表示。但是一旦使用泛型的通配符后,只能使用Object类中的共性方法,集合中元素自身方法无法使用。
通配符只能遍历、删除,不能添加修改。
示例一 通配符参数
示例二 通配符变量
public static void main(String[] args) {
Collection<Intger> list1 = new ArrayList<Integer>();
getElement(list1);
Collection<String> list2 = new ArrayList<String>();
getElement(list2);
}
public static void getElement(Collection<?> coll){}
//?代表可以接收任意类型
tips:泛型不存在继承关系 Collection list = new ArrayList();这种是错误的。
通配符高级使用----受限泛型
之前设置泛型的时候,实际上是可以任意设置的,只要是类就可以设置。但是在JAVA的泛型中可以指定一个泛型的上限和下限。
泛型的上限:
- 格式:
类型名称 <? extends A类 > 对象名称
- 意义:
只能接收该类型及其A类子类
泛型的下限:
-
格式:
类型名称 <? super B类 > 对象名称
-
意义:
只能接收该类型及其B类父类型
- <?>无限定的通配符, 是让泛型能够接受未知类型的数据
- <? extends E> 有上限通配符,能够接受指定类及其子类类型的数据,E就是该泛型的上边界
注意:这里不仅继承了父类E的子类,也可以代指显现了接口E的类
- <? super E>:有下限的通配符。能够指定其父类类型的数据,E就是该泛型类型的下边界。
注意:你可以为一个泛型指定上边界或者下边界,但是不能同时指定上下边界
比如:现已知Object类,String 类,Number类,Integer类,其中Number是Integer的父类
比如:现已知Object类,String 类,Number类,Integer类,其中Number是Integer的父类
public static void main(String[] args) {
Collection<Integer> list1 = new ArrayList<Integer>();
Collection<String> list2 = new ArrayList<String>();
Collection<Number> list3 = new ArrayList<Number>();
Collection<Object> list4 = new ArrayList<Object>();
getElement(list1);
getElement(list2);//报错
getElement(list3);
getElement(list4);//报错
getElement2(list1);//报错
getElement2(list2);//报错
getElement2(list3);
getElement2(list4);
}
// 泛型的上限:此时的泛型?,必须是Number类型或者Number类型的子类
public static void getElement1(Collection<? extends Number> coll){}
// 泛型的下限:此时的泛型?,必须是Number类型或者Number类型的父类
public static void getElement2(Collection<? super Number> coll){}
泛型的修饰符的下限
通过super关键字,在定义类的时候修饰泛型,表明泛型参数只能是Furit的子类
public class Banan <H,E extends Furit,L extends Furit> extends Furit {
private H fromPlace;
private L toPalce;
public List<H> queryFrom(int fromID){
return new ArrayList<>();
}
public List<L> queryToPlace(int fromID){
return new ArrayList<>();
}
}
泛型类的使用
定义泛型类的实现只能是Furit的子类
public class GenericTest {
public static void main(String[] args) {
Banan<String,Banan,Banan> banan = new Banan();
banan.queryFrom(1);
}
}
多个限定符的绑定
上面我们讲了,有关绑定限定的用法,其实我们可以同时绑定多个绑定,用&连接,比如:
public static <T extends Fruit&Serializable> String getFruitName(T t){
return t.getName();
}
再加深下难度,如果我们有多个泛型,每个泛型都带绑定,那应该是什么样子的呢:
public static <T extends Fruit&Serializable> String getFruitName(T t){
return t.getName();
}
大家应该看得懂,稍微讲一下:这里有两个泛型变量T和U,将T与Comparable & Serializable绑定,将U与Runnable绑定。
好了,这部分就讲完了,下面讲讲有关通配符的用法。
?与T的区别
大家可能会有疑问,那无边界通配符?与泛型变量T有什么区别呢?
答案是:他们俩没有任何联系!!!!!
泛型变量T不能在代码用于创建变量,只能在类,接口,函数中声明以后,才能使用。
比如:
public class Box<T> {
public T get(){
…………
};
public void put(T element){
…………
};
}
而无边界通配符?则只能用于填充泛型变量T,表示通配任何类型!!!!再重复一遍:?只能用于填充泛型变量T。它是用来填充T的!!!!只是填充方式的一种!!!
比如:
//无边界通配符填充
Box<?> box;
//其它类型填充
Box stringBox;
(3)、通配符只能用于填充泛型变量T,不能用于定义变量
大家一定要记得,通配符的使用位置只有:
Box<?> box;
box = new Box<String>();
即填充泛型变量T的位置,不能出现在后面String的位置!!!!
下面的第三行,第四行,都是错误的。通配符不能用于定义变量。
再次强调,?只能出现在Box<?> box;中,其它位置都是不对的。
通配符下限
通配符下限 参数 ,参数可以接受其子和其本身的类,遍历类型只能为Object <? super CompanPerson>通配符告诉编译器我们在处理一个类型CompanPerson的类型及其父类型, 但我们不知道这个父类型究竟是什么。因为没法确定,为了保证类型安全,我们就不允许往里面加入任何这种父类型的数据。同时遍历也不知道父类型是什么,因此 get的也是Object。
参数示例
通配符参数
通配符上限
通配符上限,只能遍历,不能添加,修改,但是可以删除 <? extends Fruit>通配符告诉编译器我们在处理一个类型CompanPerson的类型及其子类型, 但我们不知道这个子类型究竟是什么。因为没法确定,为了保证类型安全, 我们就不允许往里面加入任何这种类型的数据。但是可以get到CompanPerson类型的元素对象。通配符上限不允许添加修改,可以删除,只能遍历
https://www.cnblogs.com/storml/p/7997845.html
通配符上下限使用总结
/**
*
* https://www.cnblogs.com/storml/p/7997845.html
* (3) PECS法则
*
* 0.不管通配符上限还是下限,不能添加,子类型
* 总结<? extends T>/<? super T>通配符的特征,我们可以得出以下结论:
*
* 1. 如果你想在方法中从input参数里获取数据,使用<? extends T>通配符 , 只能遍历,删除
*
* 2. 如果你想在方法中把对象写入一个input参数中,使用<? super T>通配符,不能添加T 的子类型
*
* 3. 如果你既想存,又想取,那就别用通配符
*
* PECS指“Producer Extends,Consumer Super”。换句话说,如果方法中的参数表示一个生产者,就使用<? extends T>;如果它表示一个消费者,就使用<? super T>。
*/