一、泛型在继承上的体现
1、先看两段代码有何不同
片段1:
1 public void printCollection(Collection c) {
2 Iterator i = c.iterator();
3 for (int k = 0; k < c.size(); k++) {
4 System.out.println(i.next());
5 }
6 }
片段2:
1 public void printCollection(Collection<Object> c) {
2 for (Object e : c) {
3 System.out.println(e);
4 }
5 }
2、泛型在继承上的体现
如果B是A的一个子类型(子类或者子接口),而G是具有泛型声明的类或接口, G<B>并不是G<A>的子类型!
比如: String是Object的子类,但是List<String >并不是List<Object>的子类。
但是:如果类 A 是类 B的父类,A<G> 是 B<G> 的父类。
3、代码体验
实验一:
1 @Test
2 public void test(){
3
4 Object obj = null;
5 String str = null;
6 obj = str;
7
8 Object[] arr1 = null;
9 String[] arr2 = null;
10 arr1 = arr2;
11
12
13 //编译不通过
14 //Date date = new Date();
15 //str = date;
16
17
18 List<Object> list1 = null;
19 List<String> list2 = new ArrayList<String>();
20 //此时的list1和list2的类型不具有子父类关系
21 //编译不通过
22 //list1 = list2;
23
24 }
实验二:
1 public void testGenericAndSubClass() {
2 Person[] persons = null;
3 Man[] mans = null;
4 // 而 Person[] 是 Man[] 的父类.
5 persons = mans;
6
7 Person p = mans[0];
8
9
10 // 在泛型的集合上
11 List<Person> personList = null;
12 List<Man> manList = null;
13 // personList = manList;(报错)
14 }
实验三:
1 public void test(){
2
3 AbstractList<String> list1 = null;
4 List<String> list2 = null;
5 ArrayList<String> list3 = null;
6
7 list1 = list3;
8 list2 = list3;
9
10 List<String> list4 = new ArrayList<>();
11
12 }
二、通配符的使用
1、通配符
(1)使用类型 通配符:?
比如: List<?> , Map<?,?>
List<?>是List<String>、 List<Object>等各种泛型List的父类。
(2)读取 List<?> 的对象 list 中的元素时,永远是安全的,因为不管 list 的真实类型是什么,它包含的都是Object。
(3)写入 List中的元素时,不行。因为我们不知道 c 的元素类型,我们不能向其中添加对象。
注意:唯一的例外是可以写入null,它是所有类型的成员。
2、案例一
1 @Test
2 public void test() {
3 List<Object> list1 = null;
4 List<String> list2 = null;
5
6 List<?> list = null;
7
8 list = list1;
9 list = list2;
10
11 //编译通过
12 //print(list1);
13 //print(list2);
14
15
16 }
17
18 public void print(List<?> list){
19 Iterator<?> iterator = list.iterator();
20 while(iterator.hasNext()){
21 Object obj = iterator.next();
22 System.out.println(obj);
23 }
24 }
List<?> 作为 List<String> 和List<Object> 的父类。
3、通配符的使用——读取操作
(1)将任意元素加入到其中不是类型安全的:
Collection<?> c = new ArrayList<String>();
c.add(new Object()); // 编译时错误
因为我们不知道c的元素类型,我们不能向其中添加对象。 add方法有类型参数E作为集合的元素类型。
我们传给add的任何参数都必须是一个未知类型的子类。因为我们不知道那是什么类型,所以我们无法传任何东西进去。
(2)唯一的例外的是null,它是所有类型的成员。
(3)另一方面,我们可以调用get()方法并使用其返回值。返回值是一个未知的类型,但是我们知道,它总是一个Object。
4、案例
1 public static void main(String[] args) {
2 List<?> list = null;
3 list = new ArrayList<String>();
4 list = new ArrayList<Double>();
5 // list.add(3);//编译不通过
6 list.add(null);
7
8
9 List<String> l1 = new ArrayList<String>();
10 List<Integer> l2 = new ArrayList<Integer>();
11 l1.add("Hello World");
12 l2.add(15);
13 read(l1);
14 read(l2);
15 }
16 public static void read(List<?> list) {
17 for (Object o : list) {
18 System.out.println(o);
19 }
20 }
添加(写入):对于List<?>就不能向其内部添加数据。除了添加null之外。
获取(读取):允许读取数据,读取的数据类型为Object。
5、通配符的使用:注意点
(1)编译错误:不能用在泛型方法声明上,返回值类型前面<>不能使用?
public static <?> void test(ArrayList<?> list){}
(2)编译错误:不能用在泛型类的声明上
class GenericTypeClass<?>{}
(3)编译错误:不能用在创建对象上,右边属于创建集合对象
ArrayList<?> list2 = new ArrayList<?>();
三、有限制的通配符
1、有限制的通配符
<?> 允许所有泛型的引用调用
通配符指定上限
上限extends:使用时指定的类型必须是继承某个类,或者实现某个接口,即<=
通配符指定下限
下限super:使用时指定的类型不能小于操作的类,即>=
举例:
<? extends Number> (无穷小 , Number]
只允许泛型为Number及Number子类的引用调用
<? super Number> [Number , 无穷大)
只允许泛型为Number及Number父类的引用调用
2、说明
? extends A:G<? extends A> 可以作为G<A>和G<B>的父类,其中B是A的子类
? super A:G<? super A> 可以作为G<A>和G<B>的父类,其中B是A的父类
3、案例
案例1:
1 public static void printCollection3(Collection<? extends Person> coll) {
2 //Iterator只能用Iterator<?>或Iterator<? extends Person>.why?
3 Iterator<?> iterator = coll.iterator();
4 while (iterator.hasNext()) {
5 System.out.println(iterator.next());
6 }
7 }
案例2:
1 public static void printCollection3(Collection<? extends Person> coll) {
2 //Iterator只能用Iterator<?>或Iterator<? extends Person>.why?
3 Iterator<?> iterator = coll.iterator();
4 while (iterator.hasNext()) {
5 System.out.println(iterator.next());
6 }
7 }
案例3:
public void test(){
List<? extends Person> list1 = null;
List<? super Person> list2 = null;
List<Student> list3 = new ArrayList<Student>();
List<Person> list4 = new ArrayList<Person>();
List<Object> list5 = new ArrayList<Object>();
list1 = list3;
list1 = list4;
//list1 = list5;
//list2 = list3;
list2 = list4;
list2 = list5;
//读取数据:
list1 = list3;
Person p = list1.get(0);
//编译不通过
//Student s = list1.get(0);
list2 = list4;
Object obj = list2.get(0);
////编译不通过
//Person obj = list2.get(0);
//写入数据:
//编译不通过
//list1.add(new Student());
//编译通过
list2.add(new Person());
list2.add(new Student());
}
4、
四、泛型应用
1、泛型嵌套
1 public static void main(String[] args) {
2 HashMap<String, ArrayList<Citizen>> map = new HashMap<String, ArrayList<Citizen>>();
3 ArrayList<Citizen> list = new ArrayList<Citizen>();
4 list.add(new Citizen("Java"));
5 list.add(new Citizen("PHP"));
6 list.add(new Citizen("C++"));
7 map.put("Java", list);
8 Set<Entry<String, ArrayList<Citizen>>> entrySet = map.entrySet();
9 Iterator<Entry<String, ArrayList<Citizen>>> iterator = entrySet.iterator();
10 while (iterator.hasNext()) {
11 Entry<String, ArrayList<Citizen>> entry = iterator.next();
12 String key = entry.getKey();
13 ArrayList<Citizen> value = entry.getValue();
14 System.out.println("Boss: " + key);
15 System.out.println("语言成员: " + value);
16 }
17 }
2、