zoukankan      html  css  js  c++  java
  • Java 泛型(三):泛型在继承方面体现与通配符使用

    一、泛型在继承上的体现

      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、

  • 相关阅读:
    21--数据库优化
    20--mysql读写分离,分库分表
    18--mysql主从复制、及架构
    17--数据快速导出、导入,数据库迁移
    16--mysql数据备份
    15--mysql日志管理
    14--mysql锁机制
    13--mysql事务详解,数据库读现象
    etcd原理详解代码剖析
    k8s入坑之路(10)kubernetes coredns详解
  • 原文地址:https://www.cnblogs.com/niujifei/p/14801482.html
Copyright © 2011-2022 走看看