打字猴:1.700447244e+09
1700447244 public static void write(List<?extends Number>list){
1700447245
1700447246 //加入一个元素
1700447247
1700447248 list.add(123);
1700447249
1700447250 }
1700447251
1700447252 编译失败,失败的原因是list中的元素类型不确定,也就是编译器无法推断出泛型类型到底是什么,是Integer类型?是Double?还是Byte?这些都符合extends关键字的定义,由于无法确定实际的泛型类型,所以编译器拒绝了此类操作。
1700447253
1700447254 在此种情况下,只有一个元素是可以add进去的:null值,这是因为null是一个万用类型,它可以是所有类的实例对象,所以可以加入到任何列表中。
1700447255
1700447256 Object是否也可以?不可以,因为它不是Number子类,而且即使把list变量修改为List<?extends Object>类型也不能加入,原因很简单,编译器无法推断出泛型类型,加什么元素都是无效的。
1700447257
1700447258 在这种“写”操作的情况下,使用super关键字限定泛型类型的下界才是正道,代码如下:
1700447259
1700447260 public static void write(List<?super Number>list){
1700447261
1700447262 list.add(123);
1700447263
1700447264 list.add(3.14);
1700447265
1700447266 }
1700447267
1700447268 甭管它是Integer类型的123,还是Float类型的3.14,都可以加入到list列表中,因为它们都是Number类型,这就保证了泛型类的可靠性。
1700447269
1700447270 对于是要限定上界还是限定下界,JDK的Collections.copy方法是一个非常好的例子,它实现了把源列表中的所有元素拷贝到目标列表中对应的索引位置上,代码如下:
1700447271
1700447272 public static<T>void copy(List<?super T>dest, List<?extends T>src){
1700447273
1700447274 for(int i=0;i<srcSize;i++)
1700447275
1700447276 dest.set(i, src.get(i));
1700447277
1700447278 }
1700447279
1700447280 源列表是用来提供数据的,所以src变量需要限定上界,带有extends关键字。目标列表是用来写入数据的,所以dest变量需要界定上界,带有super关键字。
1700447281
1700447282 如果一个泛型结构即用作“读”操作又用作“写”操作,那该如何进行限定呢?不限定,使用确定的泛型类型即可,如List<E>。
1700447283
1700447284
1700447285
1700447286
1700447287 编写高质量代码:改善Java程序的151个建议 [:1700438170]
1700447288 编写高质量代码:改善Java程序的151个建议 建议97:警惕泛型是不能协变和逆变的
1700447289
1700447290 什么叫协变(covariance)和逆变(contravariance)?Wiki上是这样定义的:
1700447291
1700447292 Within the type system of a programming language, covariance and contravariance refers to the ordering of types from narrower to wider and their interchangeability or equivalence in certain situations(such as parameters, generics, and return types).
1700447293
[ 上一页 ]  [ :1.700447244e+09 ]  [ 下一页 ]