Java中未绑定的通配符泛型的用途和要点是什么?

时间:2011-10-06 06:55:05

标签: java generics wildcard

我不明白未绑定的通配符泛型的用途是什么。具有上边界<? extends Animal>的绑定通配符泛型非常有意义,因为使用多态性我可以使用该类型或集合。但是具有任何类型的泛型有什么意义呢?它不会破坏仿制药的目的吗?编译器没有发现任何冲突,在类型擦除后,就像没有使用泛型一样。

6 个答案:

答案 0 :(得分:27)

当您的方法并不真正关心实际类型时,未绑定类型会很有用。

一个原始的例子是:

public void printStuff(Iterable<?> stuff) {
  for (Object item : stuff) {
    System.out.println(item);
  }
}

由于PrintStream.println()可以处理所有引用类型(通过调用toString()),我们不会关注 Iterable的实际内容。< / p>

来电者可以传入List<Number>Set<String>Collection<? extends MySpecificObject<SomeType>>

另请注意,不使用泛型(使用原始类型调用)会产生完全不同的效果:它使编译器处理整个对象,就好像泛型不存在于所有。换句话说:不仅忽略了类的类型参数,还忽略了方法上的所有泛型类型参数。

另一个重要的区别是,您无法向null添加任何(非Collection<?>)值,但可以将所有对象添加到原始类型{{ 1}}:

这将无法编译,因为Collection的类型参数是未知类型(=通配符c),因此我们无法提供保证可分配给它的值(?除外,可分配给所有引用类型)。

null

如果你保留type参数(即使用原始类型),那么你可以将任何添加到集合中:

Collection<?> c = new ArrayList<String>();
c.add("foo");    // compilation error

请注意,编译器警告您不要使用原始类型,特别是出于这个原因:它删除了与泛型相关的任何类型检查。

答案 1 :(得分:6)

当您需要执行instanceof检查时。

您无法像这样进行参数化:

Object value;
if (value instanceof List<String>) {
    // ...
}

所以你这样做:

Object value;
if (value instanceof List<?>) {
    // ...
}

答案 2 :(得分:2)

对于未绑定的通配符,有(罕见的)完全正确的用例。 SDK包含其中一些。

一个示例是一种对任何类型的列表执行明确操作的方法,并且不会在rotate中返回任何Collections的内容:

static void rotate(List<?> list, int distance)

另一个例子是当你想列出一个类的可能构造函数时,方法是:

Constructor<?>[] getConstructors()

这里甚至不可能使用泛型,因为根据定义,数组将包含不同的构造函数,每个构造函数都有自己的实际类。相比之下,API确实使用通用签名来获取一个构造函数:Constructor<T> getConstructor(Class<?>... parameterTypes)

结论是,即使它主要用于与旧代码的兼容性,仍然存在未绑定的通配符泛型是正确的方法。

答案 3 :(得分:1)

虽然使用原始类型意味着你不了解泛型(因为你很懒或很久以前写过代码),使用<?>意味着你了解泛型并明确强调你的代码可以工作与任何类型的对象。

答案 4 :(得分:1)

请允许我重新解释一下这个问题:

List<Object>List<?>之间有什么区别?”

答案是List<?>限制性更强。它告诉我们,我们有一堆某种类型的对象,但该类型不一定是Object

由于我们不知道该类型是什么,我们无法添加到列表中 - 我们添加的任何内容都可能是错误的类型。事实上,我们不能将?类型的任何参数传递给任何方法,而不仅仅是add()

从好的方面来说,当我们指定方法需要List<?>时,可以使用List<String>List<Integer>或任何其他List<>List<Object>只能List<Object>

答案 5 :(得分:0)

使用无界通配符只有在包装不使用泛型的旧代码时才有意义,AFAIK,基本上是集合。

如果你看看你能用这种通用做什么,它基本上是 nothing 。 如果你有一个集合你不能添加任何东西,如果你试着读一些东西,你总会得到Object等等。

这反过来有助于保证您将以类型安全的方式处理数据,而使用原始类型会导致编译器忽略您所做的任何混乱。

来自Which methods and fields are accessible/inaccessible through a reference variable of a wildcard parameterized type?的{p> Angelika Langers Java Generics FAQ可能会引起人们的兴趣。