java泛型-PECS

 1 package com.example.base;
 2 
 3 import java.util.ArrayList;
 4 import java.util.List;
 5 
 6 import com.example.spring.MyLog;
 7 /**
 8  * Producer extends Consumer super  生产者使用extends,consumer使用super
 9  * 这里的生产者和消费者是相对容器而言的,
10  *   生产者只能对外提供数据,不可以写入数据,数据来源于赋值操作(将参数化类型为子类的容器赋值过来)
11  *   消费者表示只能向容器中写入数据,不能读取(只能以Object来接收)
12  * 这里的extends和super指的是声明类型和参数化类型的关系,
13  *    如下所示:等号左侧类型为声明类型,右侧为参数化类型
14  *    List<? extends Number> intList = new ArrayList<Integer>();
15  *    private List<? super Number> intList2 = new ArrayList<Number>();
16  * @DESC 
17  * @author guchuang
18  *
19  */
20 public class PECS {
21 
22     int int1 = 1;
23     long long1 = 11;
24     Number number1 = 10;
25     
26     private List<Integer> intList = new ArrayList<Integer>();
27     private List<Long> longList = new ArrayList<Long>();
28     private List<Number> numberList = new ArrayList<Number>();
29     
30     public static void main(String[] args) {
31         PECS pecs = new PECS();
32         pecs.pe();
33         pecs.cs();
34     }
35     
36     /**
37      * <? extends Number>  这种方式声明的泛型容器,不能写入任何类型的数据,只能读取数据
38      * 其指定了上确界为Number,参数化类型(如:实际新建的容器类型T new ArrayList<T>())必须是Number的子类,所以读出的数据都可以上转型为Number
39      * 理论含义是容器内包含的数据可能是Number的任何一种子类,所以无法添加数据。
40      * 写数据的方式:
41      *    声明一个具体类型(Number的子类型)的容器,向其中添加数据,将这个容器赋值给numbers容器
42      * 优势:
43      *    避免调用者向此容器内写入数据,只能读取里面的数据
44      */
45     public void pe() {
46         //<? extends Number>  这种方式声明的泛型容器,不能写入任何类型的数据
47         List<? extends Number> numbers = new ArrayList<Number>();
48         //下面三种添加数据都会导致编译报错
49         //foo.add(int1);
50         //foo.add(long1);
51         //foo.add(number1);
52         
53         //Number number = numbers.get(0);
54         
55         intList.add(123);
56         intList.add(456);
57         //将新创建的具有确定类型的容器(必须是Number的子类型)赋值给numbers,起到生产数据的目的
58         numbers = intList;      //新容器的参数化类型是Integer,是Number的子类,所以可以赋值
59         MyLog.info(numbers);
60         Number number = numbers.get(0);    //读出来的类型依然是Number
61         MyLog.info("read from ? extends Number: " + number);
62         numbers = longList;
63         numbers = numberList;
64     }
65     
66     /**
67      * Consumer super
68      * ? super Number 表示容器中所有的数据类型都是Number或者Number的超类型,
69      *  所以Number及其子类型(可以上转型为Number)可以写入,读取的时候由于不能确定类型,只能使用Object接收
70      */
71     public void cs() {
72         List<? super Number> numbers = new ArrayList<Number>();
73         numbers.add(int1);
74         numbers.add(long1);
75         numbers.add(number1);
76         //numbers.add(new Object());    编译报错
77         MyLog.info(numbers);
78         
79         //Number n = numbers.get(0);    编译报错
80         Object n = numbers.get(0);      //只能以Object来接收数据
81         //numbers = intList;    编译报错
82         numbers = numberList;
83         numbers = new ArrayList<Object>();
84     }
85 }