Java 通配符

当没有使用通配符的情况下,我们定义一个方法:

 

1

2

3

4

public static <E> void test(List<E> l){

    E e = l.get(0);

    l.set(0, e);

}

我们从List中 get和set都没有问题,因为这个E 它的类型是某种明确的类型。

而当使用通配符时来描述参数时,就有些不同了。
我们先定义一下两种通配符:
<? extends E> 是 Upper Bound(上限) 的通配符
<? super E> 是 Lower Bound(下限) 的通配符

1) 当使用 Upper Bound 通配符时:

 

1

2

3

4

public static void test(List<?> list){

    Object e = list.get(0); // get OK

    list.set(0, e);         // set 编译报错

}

上面代码中通配符<?><? extends Object> 的简写。(关于<?>是否和<? extends Object>完全等价,我遇到个小插曲,在结束的时候来描述)

在eclipse里错误提示为:

The method set(int, capture#2-of ?) in the type List<capture#2-of ?> is not applicable for the arguments (int, Object)

注: <capture#2-of ?> 是一个占位符,表示编译器对通配符的捕获,更多见:
http://www.ibm.com/developerworks/cn/java/j-jtp04298.html

set报错的原因是因为此时方法中的类型是不可具体化的(reified),你可以传递一个String,Number,Book,等任何继承自Object的类作为List的参数类型给test方法,而list要求集合中的类型必须是一致的,set的时候没有办法保证set进去的数据类型是否和list中原本的类型一致,比如你传给test方法的是 List<Book>, 那么在方法中set进去一个Object显然类型就不一致了。这也是通配符带来灵活性的同时所要付出的代价。

结论:使用了 <? extends E> 这样的通配符,test方法的参数list变成了只能get不能set(除了null) 或者不严谨的说它变成了只读参数了, 有些类似一个生产者,提供数据。

 

2) 当使用 Lower Bound 的通配符时:

 

1

2

3

4

5

6

7

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

    Number n = list.get(0);             // 编译错误

    Object o = list.get(0);             // OK

    list.set(0, new Object());          // 编译错误

    list.set(0, new Long(0));           // OK

    list.set(0, new Integer(0));        // OK

}

这时get只能get出最宽泛的父类型,即Object。
这时set的时候,必须是Number或Number的子类。
原因和上面的get类似。

结论: 使用了<? super E> 这种通配符,test方法的参数list的get受到了很大的制约,只能最宽泛的方式来获取list中的数据,相当于get只提供了数据最小级别的访问权限(想想,你可能原本是放进去了一个Book,却只能当作Object来访问)。它更多适合于set的使用场景,像是一个消费者,主要用来消费数据。

上面便是对通配符的使用原则的说明,简单的说 PECS原则是指导我们在泛型方法中使用通配符的直接原则。参数作为生产者使用<? extends E>,作为消费者时使用<? super E>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值