zoukankan      html  css  js  c++  java
  • Java的泛型和通配符

    泛型:
    1.泛型类
        class A<T>{
        }
    2.在创建实例时,需要为其类型变量赋值

    3.泛型方法
        class A<T>{
            public T fun1(){}
            public void fun2(T t){}
            //以上两个都不是泛型方法,他们是泛型类里面的一个方法
            //发现方法要求需要在方法上有泛型的定义
            public <T> T fun3(){}//此为泛型方法
        }

        class B{
            public <T> fun1(){}//也为泛型方法,泛型方法不一定要在泛型类中
        }
    *泛型方法和泛型类并没有直接的关系,

    4.泛型类的使用
        *泛型类中定义的泛型
            >可以在方法的返回值中使用
            >可以在方法的参数中使用
            >可以在局部变量是使用
        class C<T>{
            public T fun1(){
                T t = ...//可以的
                new T()//不可以的,会报错
            }
            public void fun2(T t){}
        }
    简单来记:泛型可以在左边使用而不可以在右边使用。

    5.泛型的继承和实现
        *子类不是泛型类:需要给父类传递一个具体的类型常量
            >此时父类中所有的泛型参数都会被此类型常量给替换掉
        *子类是泛型类:可以给父类传递一个具体的类型参数,也传递一个泛型参数
        class AA1 extends A<String>{}
        class AA2<E> extends A<E>{}


    =========================================
    =========================================
    =========================================

    泛型的通配符

    1. 通配符使用的场景

      方法的形参!

    2. 通配符的优点
      使方法更加通用!

    3. 通配符分类
      无界通配:?
      子类限定:? extends Object
      父类限定:? super Integer

    4. 通配符缺点
      使变量使用上不再方便
      无界:参数和返回值为泛型的方法,不能使用!
      子类:参数为泛型的方法不能使用
      父类:返回值为泛型的方法不能使用

    5. 比较通配符
    boolean addAll(Collection<E> c)

    List<Number> numList = new ArrayList<Number>();
    List<Integer> intList = new ArrayList<Integer>();
    numList.addAll(intList);//addAll(Collection<Number> c), 传递的是List<Integer>,报错


    boolean addAll(Collection<? extends E> c)

    List<Number> numList = new ArrayList<Number>();
    List<Integer> intList = new ArrayList<Integer>();
    numList.addAll(intList);//addAll(Collection<? extends Number> c), 传递的是List<Integer>,通过

    代码演示

     1 package genericity;
     2 
     3 public class Demo1 {
     4 
     5    class A<T>{
     6        private T t;
     7        public T fun1(){
     8            return t;
     9        }
    10        
    11        public void fun2(T t){
    12            
    13        }
    14        
    15    }//是泛型类
    16    
    17    class B extends A<String>{}//B就不是泛型类
    18    
    19    class C<E> extends A<Integer>{}//也是泛型类
    20    
    21    class D<E> extends A<E>{}//也是泛型类
    22    
    23    public void fun1(){
    24        D<String> d = new D<String>();//此时class D 和 class E 中的泛型都被String给替换了
    25    }
    26 }
      1 package genericity;
      2 
      3 import java.util.ArrayList;
      4 import java.util.List;
      5 
      6 import org.junit.Test;
      7 
      8 public class Demo2 {
      9 
     10     @Test
     11     public void fun1(){//集合和数组的较量
     12         /*
     13          * 第一次较量
     14          * 数组:我可以创建一个什么都可以存在的10空间
     15          * 集合:我可以创建一个什么都放而且无限的空间
     16          */
     17         Object[] arr1 = new Object[10];
     18         List list1 = new ArrayList();
     19         
     20         /*
     21          * 第二次较量
     22          * 数组:我可以创建一个只存放String类型的10空间
     23          * 集合:在以前我不行,不过现在我也可以,我可以创建一个只存放String类型的无限空间。
     24          */
     25         String[] arr2 = new String[10];
     26         List<String> list2 = new ArrayList<String>();
     27         
     28         /*
     29          * 第三次较量
     30          * 数组:我可以使用Object[]来存在String[],但是arr3[0] = new Integer(100);//编程不报错,运行报:ArrayStoreException
     31          * 集合:因为泛型的擦除,直接不给我编译通过 List<Object> list3 = new ArrayList<String>()
     32          */
     33         Object[] arr3 = new String[10];
     34         arr3[0] = new Integer(100);//编程不报错,运行报:ArrayStoreException
     35         
     36 //        List<Object> list3 = new ArrayList<String>();
     37           /**
     38            * 上面的代码报错,因为泛型只有编译器认识,而JVM对泛型根本不识别,泛型会在
     39            * 运行时擦除,如果上面代码不报错,而且运行时泛型又会擦除,那么就好出现下面的笑话
     40            * list.add(new Integer(100)),那么数组就好笑话集合,你什么东西都能放,
     41            * 还有什么限制,笑话。
     42            * 
     43            * 然后我们把这个问题放大,对一个打印集合里面数据的方法,
     44            */
     45     }
     46     
     47     public void fun2(){
     48         List<Integer> intList = new ArrayList<Integer>();
     49         
     50         List<String> strList = new ArrayList<String>();
     51 //        print1(intList);//直接报错,原因和上面的一样,因为有一个实参向形参赋值的过程,编译器直接不让通过 List<Object> list= intList=new ArrayList<Integer>();
     52         //思考:那每个不同类型的集合都需要不同的打印方法,那方法是也太多了,所以就有了通配符的出现
     53         
     54         //这样就可以使用通用的打印方法了
     55         print2(intList);
     56         print2(strList);
     57     }
     58     
     59     public void print1(List<Object> list){
     60         
     61     }
     62     
     63     /**
     64      * 这里的?就是通配符
     65      * @param list
     66      */
     67     public void print2(List<?> list){
     68         /*
     69          * 思考:虽然都可以调用了,但是却带来了一些参数使用上面的限制
     70          */
     71 //        list.add(new Integer(100));//报错,因为并不知道传递进来的到底是上面,如果是String,那编程通过就笑话了,add()作废
     72         Object obj = list.get(0);//其实这个参数可以使用的原因是因为Object为所有类的父类,不让这个get()方法也作废
     73         
     74         /*
     75          * 小结:
     76          *      1、当使用通配符时,对泛型类中的参数为泛型的方法起到了副作用,不能再使用!
     77          *      2、当使用通配符时,泛型类中返回值为泛型的方法,也作废了!
     78          * 通配符的好处:可以使泛型类型更加通用!尤其是在方法调用时形参使用通配符!
     79          */
     80     }
     81     
     82     public void fun3(){
     83         List<Integer> intList = new ArrayList<Integer>();
     84         List<Long> longList = new ArrayList<Long>();
     85         print3(intList);
     86         print3(longList);
     87     }
     88     
     89     /**
     90      * 子类统配,必须是Number及Number的子类才可以传参
     91      * 这样的缺点是:降低了参数的灵活性,但是关闭一扇大门就会打开一扇大门
     92      * 因为所有累都是Number的子类,所有返回值可以使用Number来接受,get()方法获得解放,即返回值为泛型的方法可以使用了
     93      * @param list
     94      */
     95     public void print3(List<? extends Number> list){
     96         Number nu = list.get(0);//正确
     97 //        list.add(new Integer(100));//但add()方法还是被废,以为不知道具体传入的哪一个子类,如果传入的是Long,加入Integer就笑话了
     98     }
     99     
    100     /**
    101      * 父类统配,只允许Integer传递参数
    102      * 这样的缺点是:降低了参数的灵活性,但是关闭一扇大门就会打开一扇大门
    103      * 好处是因为所有类都是Integer的父类,参数为泛型的所有方法都可以使用了
    104      * 但是相反的,返回值为泛型类型的方法就不能使用,因为子类不能接收父类的值
    105      * @param list
    106      */
    107     public void print4(List<? super Integer> list){
    108         list.add(new Integer(100));//正确
    109         /*
    110          * 但返回值为泛型的方法就不能使用了
    111          */
    112 //        Integer nu = list.get(0);//报错
    113     }
    114     
    115     
    116 }
  • 相关阅读:
    linux(CENTOS)系统各个目录的作用详解
    2018 焦作E java 高精度暴力
    [SHOI2015]激光发生器,计算几何 直线相交
    codeforces 600E dfs+线段树合并
    2018 南京区域赛A SG打表
    8个常见的硬币博弈的SG值规律
    hdu 3389 阶梯博弈
    组合游戏与博弈好文
    gym 100500B 多项式哈希+Rabbin-Karp/最小表示法
    zjoi 2007 捉迷藏 动态点分治+可删堆
  • 原文地址:https://www.cnblogs.com/yghjava/p/6298284.html
Copyright © 2011-2022 走看看