java基础-泛型

先来看下面这段代码,map被声明为Map<String, String>类型

1         Map<String, String> map = new HashMap<>();
2         map.put("hello", "你好");
3         map.put("how are you?", "吃了没?");
4         System.out.println(map.get("hello"));
5         System.out.println(map.get("how are you?"));

再来看这段代码反编译后的情况

1         Map<String, String> map = new HashMap();
2         map.put("hello", "你好");
3         map.put("how are you?", "吃了没?");
4         System.out.println((String)map.get("hello"));
5         System.out.println((String)map.get("how are you?"));

 

泛型,又称作参数化类型,顾名思义是给类型增加了参数,那么为什么要给类型增加参数呢?设想不加参数的情况,map.get的返回类型是Object,我们在使用该返回对象时必须手动强制转换成需要的类型才能进行相应操作(jdk5之前就不得不这样做),手动强制转换就存在类型安全问题(ClassCastException),所以泛型出现了。说白了,java的泛型就是编译器替你进行强制转换,并在编译期就能提前发现类型安全问题。

 

泛型的使用

泛型接口、泛型类、泛型方法

 1 //GenericInterface也可以指定泛型类型,如String,其实现genericInterface也需要为String。
 2 //但如果GenericInterface需要泛型T,T必须要在GenericClazz上先声明,不然无法识别。
 3 public class GenericClazz<T> implements GenericInterface<T> {
 4     private T t;
 5 
 6     //对应GenericClazz上的T
 7     public GenericClazz(T t) {
 8         this.t = t;
 9     }
10     //GenericInterface接口方法的实现
11     @Override
12     public void genericInterface(T t) {
13         System.out.println(t.getClass().getName());
14     }
15     //泛型方法的泛型可以覆盖泛型类上的泛型
16     public <T> void genericFunction(Class<T> clazz) {
17         System.out.println(clazz.getName());
18     }
19 }
20 
21 public interface GenericInterface<T> {
22     void genericInterface(T t);
23 }

 

泛型中的通配符,以及指定泛型的上下限

 1 public class GenericWildcard {
 2     @Test
 3     public void test() {
 4 
 5         Box<String> name = new Box<>("corn");
 6         Box<Integer> age = new Box<>(12);
 7         Box<Number> number = new Box<>(345);
 8 
 9         getData(name);
10         getData(age);
11         getData(number);
12 
13 //        getCeilingNumberData(name);//编译出错
14         getCeilingNumberData(age);
15         getCeilingNumberData(number);
16 
17 //        getFloorIntegerData(name);//编译出错
18 //        getFloorIntegerData(age);//编译出错
19         getFloorIntegerData(number);
20     }
21 
22     private void getData(Box<?> data) {
23         System.out.println("data :" + data.getData());
24     }
25     private void getCeilingNumberData(Box<? extends Number> data){//指定Number为泛型的上限,Integer、Number符合
26         System.out.println("data :" + data.getData());
27     }
28     private void getFloorNumberData(Box<? super Number> data){//指定Number为泛型的下限,只有Number符合
29         System.out.println("data :" + data.getData());
30     }
31 }

 

Box类型

 1     public class Box<T> {
 2 
 3         private T data;
 4 
 5         public Box() {
 6         }
 7 
 8         private Box(T data) {
 9             setData(data);
10         }
11 
12         private T getData() {
13             return data;
14         }
15 
16         private void setData(T data) {
17             this.data = data;
18         }
19     }
View Code

 

泛型常被容器类使用,因为容器中所“陈放”的东西的类型待确定,泛型在通过反射实例化对象时也十分好用。

1     private <T> T instance(Class<?> clazz) throws Throwable {
2         T t = (T) clazz.newInstance();
3         return t;
4     }
5     @Test
6     public void testInstance() throws Throwable {
7         Object o = instance(Class.forName("com.zyong.generic.GenericWildcard"));
8         System.out.println(o.getClass().getName());
9     }

 

PECS

所谓PECS是指producer-extends,consumer-super,即如果参数化类型表示一个T生产者,就使用<? extends T>;如果它表示一个T消费者,就使用<? super T>。Comparable、Comparator都是消费者。我是这样理解的,对于<? extends T>,能确定的只有类型的上限T,我们只能对它进行读操作,写操作是危险的(比如实际类型为B,而写入了B的父类A,A是T的子类,外部操作时就会出现错误)。对于<? super T>,能确定的只有类型的下限T,那么我们可以放心的写入类型T,这样的操作对于外界是安全的(因为外界只看到父类)。

 

参考:http://www.cnblogs.com/lwbqqyumidi/p/3837629.html

  https://stackoverflow.com/questions/2723397/what-is-pecs-producer-extends-consumer-super?rq=1

posted @ 2017-08-02 18:39  holoyong  阅读(173)  评论(0编辑  收藏  举报