Java Generics 泛型汇总

1. 泛型类。在类名后面声明泛型变量。

class GenericMap<T extends Number, E extends Date> extends HashMap<T, List<E>> {

    ....

}

new GenericMap<Integer, Time>()的时候才最终绑定T(Integer)和E(Time)。所以这个map的get方法实际上变成了

public List<Time> get(Integer key) {

    return super.get(key);

}

 

2. 泛型方法。在返回值之前申明泛型变量。

public static <T, E extends Number> int getSize(Map<T, List<E>> map) {

    return map.size();

}

综上所述,泛型变量只能在类名后面方法的返回值前面声明。注意泛型变量可以不加任何约束<T>,或者只能用上限<T extends Number>,不能用下限,后面将提到。

 

3. Java的泛型并不能很好的支持多态

Example: List<Number> list = new ArrayList<Integer>(); // 编译错误

 

Example: 

public static void testGeneric1(List<Number> list) {

    // ...

}

...

testGeneric1(new ArrayList<Integer>()); // 编译错误

...

 

这时候必须用List<? extends Number>来代替List<Number>。这就要使用通配符(?)了

 

4. wildcast泛型通配符? 泛型上限和下限 bound

上面例子提到用<? extends Number>来解决编译错误,这是用到了泛型的上限,同理还可以定义下限,比如<? super Number>.

 

上边界限定通配符 <? extends T>,T是类型参数上界

public void upperBound1(List<? extends Number> list) {  

Number number = list.get(0); // 可见上限主要是用于从容器中往外取元素的,取出的内容都可视为其上限类型T

   list.add(number); // 这句话无法通过编译,因为在运行时,传入的参数可能是List<Integer>

}

 

如果非要写的话,所以这个方法可以这么写

public <T extends Number> void upperBound2(List<T> list) {  

Number number = list.get(0);

   list.add((T)number); // 除非作强制类型转换,否则父类型是无法放入字类型容器中的。

}

 

下边界限定通配符 <? super T>,T是类型参数的下界

public void lowerBound1(List<? super Number> list) {  

    Number number = list.get(0); // 编译错误。因为在运行时,传入的参数可能是List<Object>,须作强制类型转换

   list.add(number); // 可见下限主要是用于往容器中放 下限类型T 的对象

}

 

无边界通配符<?>, 不做任何限制

不能读取(读出的类型为?,因此无法使用),也不能写入,只能用跟通配类型无关的一些API

public void unBound(List<?> list) {  

    list.size();

}

 

PECS原则:

如果要从集合中读取类型T的数据,并且不能写入,可以使用 ? extends 通配符;(Producer Extends)

如果要从集合中写入类型T的数据,并且不需要读取,可以使用 ? super 通配符;(Consumer Super)

public <T> void copy(List<? super T> dest, List<? extends T> src) 

{

  for (int i=0; i<src.size(); i++) {

    dest.set(i,src.get(i)); 

  }

}

 

综上所述,泛型通配符只能用在变量声明(定义)方法的形参声明。泛型通配符可以不加任何约束<?>,或者用上限<? extends T>或下限<? super T>。

 

5. <?>和<Object>的区别

List<?> list 表示 list 是持有某种特定类型的 List,但是不知道具体是哪种类型。那么我们可以向其中添加对象吗?当然不可以,因为并不知道实际是哪种类型,所以不能添加任何类型,这是不安全的。而单独的 List list ,也就是没有传入泛型参数,表示这个 list 持有的元素的类型是 Object,因此可以添加任何类型的对象,只不过编译器会有警告信息。

猜你喜欢

转载自dearls.iteye.com/blog/2343011