未绑定通配符泛型在 Java 中的用途和意义是什么?

2022-09-01 11:54:04

我不明白未绑定通配符泛型的用途是什么。具有上限的绑定通配符泛型非常有意义,因为使用多态性,我可以处理该类型或集合。但是,拥有可以是任何类型的泛型有什么意义呢?难道它违背了泛型的目的吗?编译器没有发现任何冲突,并且在类型擦除后,就像没有使用泛型一样。<? extends Animal>


答案 1

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

一个原始的例子是这样的:

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

由于可以处理所有引用类型(通过调用),我们并不关心它的实际内容是什么。PrintStream.println()toString()Iterable

并且调用方可以传入 a 或 a 或 a 。List<Number>Set<String>Collection<? extends MySpecificObject<SomeType>>

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

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

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

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

如果省略 type 参数(即使用原始类型),则可以向集合中添加任何内容

Collection c = new ArrayList<String>();
c.add("foo");
c.add(new Integer(300));
c.add(new Object());

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


答案 2

当您需要执行检查时。instanceof

您不能像这样参数化:

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

所以你要:

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

推荐