1700447179
1700447180
如此一来,编译时就不会给出“unchecked”警告了。现在新的问题出现了:如果期望list2是一个Integer类型的列表,而不是Object列表,因为后续的逻辑会把Integer类型加入到list2中,那该如何处理呢?
1700447181
1700447182
强制类型转化(把asList强制转换成List<Integer>)?行不通,虽然Java的泛型是编译擦除式的,但是List<Object>和List<Integer>没有继承关系,不能进行强制转换。
1700447183
1700447184
重新声明一个List<Integer>,然后读取List<Object>元素,一个一个地向下转型过去?麻烦,而且效率又低。
1700447185
1700447186
最好的解决方法是强制声明泛型类型,代码如下:
1700447187
1700447188
List<Integer>list2=ArrayUtils.<Integer>asList();
1700447189
1700447190
就这么简单,asList方法要求的是一个泛型参数,那我们就在输入前定义这是一个Integer类型的参数,当然,输出也是Integer类型的集合了。
1700447191
1700447192
(3)变量list3
1700447193
1700447194
变量list3有两种类型的元素:整数类型和浮点类型,那它生成的List泛型化参数应该是什么呢?是Integer和Float的父类Number?你太高看编译器了,它不会如此推断的,当它发现多个元素的实际类型不一致时就会直接确认泛型类型是Object,而不会去追索元素类的公共父类是什么,但是对于list3,我们更期望它的泛型参数是Number,都是数字嘛!参照list2变量,代码修改如下:
1700447195
1700447196
List<Number>list3=ArrayUtils.<Number>asList(1,2,3.1);
1700447197
1700447198
Number是Integer和Float的父类,先把三个输入参数向上转型为Number,那么返回的结果也就是List<Number>类型了。
1700447199
1700447200
通过强制泛型参数类型,我们明确了泛型方法的输入、输出参数类型,问题是我们要在什么时候明确泛型类型呢?一句话:无法从代码中推断出泛型类型的情况下,即可强制声明泛型类型。
1700447201
1700447202
1700447203
1700447204
1700447206
编写高质量代码:改善Java程序的151个建议 建议96:不同的场景使用不同的泛型通配符
1700447207
1700447208
Java泛型支持通配符(Wildcard),可以单独使用一个“?”表示任意类,也可以使用extends关键字表示某一个类(接口)的子类型,还可以使用super关键字表示某一个类(接口)的父类型,但问题是什么时候该用extends,什么时候该用super呢?
1700447209
1700447210
(1)泛型结构只参与“读”操作则限定上界(extends关键字)
1700447211
1700447212
阅读如下代码,想想看我们的业务逻辑操作是否还能继续:
1700447213
1700447214
public static<E>void read(List<?super E>list){
1700447215
1700447216
for(Object obj:list){
1700447217
1700447218
//业务逻辑操作
1700447219
1700447220
}
1700447221
1700447222
}
1700447223
1700447224
从List列表中读取元素的操作(比如一个数字列表中的求和计算),你觉得方法read能继续写下去吗?
1700447225
1700447226
答案是:不能,我们不知道list到底存放的是什么元素,只能推断出是E类型的父类(当然,也可以是E类型,下同,不再赘述),但问题是E类型的父类是什么呢?无法再推断,只有运行时才知道,那么编码期就完全无法操作了。当然,你可以把它当作是Object类来处理,需要时再转换成E类型—这完全违背了泛型的初衷。
1700447227
1700447228
在这种情况下,“读”操作如果期望从List集合中读取数据就需要使用extends关键字了,也就是要界定泛型的上界,代码如下:
[
上一页 ]
[ :1.700447179e+09 ]
[
下一页 ]