一、泛型在继承上的体现

  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、泛型在继承上的体现

    如果BA的一个子类型(子类或者子接口),而G是具有泛型声明的类或接口, G<B>并不是G<A>的子类型!

    比如: StringObject的子类,但是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中的元素时,不行。因为我们不知道 的元素类型,我们不能向其中添加对象。
        注意:唯一的例外是可以写入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、

 

posted on 2021-05-23 16:49  格物致知_Tony  阅读(448)  评论(0编辑  收藏  举报