Java中的无界通配符<?>在什么时候使用

本文首发于掘金

List<?>List<Object> 的区别

区别:

  1. List<?>变量的元素只能读,不能写(可以插入null元素)
  2. List<Object>不是List<String>的父类,但List<?>是所有List泛型的父类,因此List<?>变量可以被赋值为多种List泛型类型
public static void printList(List<Object> list) {
    for (Object elem : list)
        System.out.println(elem + " ");
    System.out.println();
}

上面代码中定义的方法只能接受List<Object>类型的变量为参数,不能接受List<String>,改成List<?>的话就可以接受了。

List<?>List 的区别

List<?>是所有List泛型的父类,而List是List泛型的原类型(raw type)。允许使用List原类型是为了兼容引入泛型前的代码,使用原类型会失去泛型的安全性和表达性,可能在运行时报错,还需要自己转型。因此编译器会给出警告。

注意,有一些需要使用原类型的场景:

  1. 在类的字面量中必须使用原类型,List.classString[].classint.class 是正确的,但 List<?>.class List<String>.class 是错误的。
  2. instanceof 操作符中使用原类型就够了,因为泛型信息会在运行时擦除,在 instanceof 操作符中只能使用无界通配符类型或原类型,而且两者并没有区别,推荐后者。
// instanceof 操作符的推荐使用方式
if (o instanceof Set) {
    Set<?> s = (Set<?>) o; // 这种转型时有检查的,不会有编译时警告
}

<?> 的使用场景

泛型通配符的in-out使用规则中:

  1. 用来读取的List变量(in),使用extend定义下界;能使用<Object>通配符的地方,就改用无界通配符<?>
  2. 用来写入的List变量(out),使用super定义上界
  3. 当List变量同时需要in-out访问时,不使用通配符

例如JDK源码中List接口的的containsAll、removeAll方法都是用<?>定义的:

boolean containsAll(Collection<?> c);
boolean removeAll(Collection<?> c);

而addAll方法,虽然也是读取,但是在后续使用时,会调用E的方法,因此不能使用<Object>通配符。

boolean addAll(Collection<? extends E> c);

参考备注

  1. 参考了Oracle Java文档 Unbounded WildcardsGuidelines for Wildcard Use
  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值