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 }

转载于:https://www.cnblogs.com/zhangrj9/p/9872626.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值