使用带有通配符的“Java”泛型类型“?”

时间:2014-09-25 00:26:04

标签: java generics wildcard

在尝试了解Java通用类型和通配符#34;?"的用法时,我尝试了以下内容:

  1. List<?> li = new ArrayList<Integer>();
  2. List<Integer> li2 = new ArrayList<Integer>();
  3. li2.add(new Integer(6));
  4. li = li2;
  5. 以上编译并运行正常。但如果我尝试:

    li.add(new Integer(5));
    

    我遇到编译错误(使用Oracle JDeveloper作为IDE):

    Error(24,9):  cannot find method add(java.lang.Integer)
    

    为什么以上不编译但作业li=li2没问题?另外,如果我想调用li.add(...)什么是可接受的参数值?

2 个答案:

答案 0 :(得分:3)

?是一个通配符类型,包含所有引用类型。将分配给类型?的值必须可分配给任何引用类型。 Integer不能分配给所有引用类型(例如,String s = new Integer(1);失败)。实际上,在Java中,可分配给所有引用类型的唯一值是null,这是您可以添加到List<?>的唯一值

其他有趣的组合:

? super Number是包含ObjectNumber类型的范围。当你写这样一个值时,它必须是ObjectNumber,即。 Integer会好的。阅读此类值时,它将为ObjectNumber(因此,Object)。

? extends Number是包含类型Number及其所有子类型的范围。当你写这样一个值时,它必须是Number的所有子类型的类型,即。它必须是null。读取这样的值时,它将是Number

答案 1 :(得分:2)

对“li”的调用不会打扰您是分配了ArrayList<Integer>还是LikedList<String>,它只会对声明的类型List<?>起作用。

声明泛型参数时,它可以应用于返回类型和方法参数。例如,在List<String>中,您将拥有String get(int i)void add(String)方法。

两者都是安全的,因为使用这种方法你只能从列表中添加(和检索)String。

List<?>上,您将拥有Object get(int i)方法,因为列表中的任何内容都可以安全地转换为Object,无论是Integer还是String。

但是,提供void add(Object)方法是不安全的,因为会允许您将String添加到整数列表,反之亦然(或任何其他东西)。