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 }
  • 相关阅读:
    IntelliJ IDEA 14.03 java 中文文本处理中的编码格式设置
    应聘感悟
    STL string分析
    CUDA SDK VolumeRender 分析 (1)
    BSP
    CUDA SDK VolumeRender 分析 (3)
    CUDA SDK VolumeRender 分析 (2)
    Windows软件发布时遇到的一些问题
    Ten Commandments of Egoless Programming (转载)
    复习下光照知识
  • 原文地址:https://www.cnblogs.com/yghjava/p/6298284.html
Copyright © 2011-2022 走看看