在 JAVA 泛型中,为什么这无效:
List<?> l = new ArrayList()<?>;
考虑到这是有效的:
public interface someList<?>{}
有两个无界通配符。在我看来,它们都相当于:
List l = new ArrayList();
和
public interface someList {}
我哪里错了?
List<?>
表示任何一种类型。为了让您作为程序员从类型检查中受益,设计师决定您需要在实例化期间提供一种类型。
如果你想要充分的灵活性,List<?> l = new ArrayList<Object>()
这是要走的路。
通配符?
只是一种说法,是的,我想要泛型,但不关心哪种类型。与无泛型变体不同,您仍然会在必要时获得类型检查和编译器警告。
因为,你不能实例化一个ArrayList
未知类型。
您可以实例化一个ArrayList
原始类型。
new ArrayList();
或者,您可以实例化ArrayList
Object或某些特定的已知类型。
new ArrayList<Object>();
new ArrayList<String>();
只需这样做:
class CrazyBogusUnrelatedType { }
List<?> l = new ArrayList<CrazyBogusUnrelatedType>();
真的。这是 100% 正确的,并且 100% 类型安全。这表明您可以在其中使用任意东西。这也证明了这样做的荒谬性。
在我看来,它们都相当于:
甚至没有远程关闭。它们是完全相反的。
使用List l
,您可以向其中添加任何内容。使用List<?> l
,您不能向其中添加任何内容,除了null
。所以基本上,你初始化的列表List<?> l = new ArrayList()<?>;
几乎完全没用,因为它是空的,而且你只能添加null
到它,它唯一可以包含的东西就是null
元素。
这是使用通配符的结果。回想一下 PECS(生产者extends
,消费者super
)规则——你在extends
这里有一个通配符(无界通配符在大多数情况下与 相同extends Object
),所以它只用作生产者。除了没有任何东西可以生产——它是空的。那么为什么你会想要这个呢?
因为你试图构造一个泛型类型的对象,这是无稽之谈。如果创建了一个对象,它可能不会同时具有多种类型,因为 Java 不模拟量子世界。通配符类型表示预先不知道类型参数,但是当您有值时它将是一些具体的类型。
这并不等同于List l = new ArrayList();
因为后者确实只允许静态类型 Object 的值,但是在泛型的帮助下,您可以将类型限制为任何引用类型。(尽管此信息仅在编译时存在)