通配符背后的目的是什么?它们与generics有何不同?

我几天前从未听说过野猫,在读完老师的Java书之后,我仍然不确定它是什么,为什么我需要使用它。

假设我有一个超级Animal和几个子类,如DogCatParrot等……现在我需要有一个动物列表,我的第一个想法是这样的:

 List listAnimals 

相反,我的同事们推荐的内容如下:

 List listAnimals 

为什么我应该使用通配符而不是简单的generics?

假设我需要一个get / set方法,我应该使用前者还是后者? 他们怎么这么不同?

声明局部变量时,通配符没有多大意义,但是在为方法声明参数时它们非常重要。

想象一下你有一个方法:

 int countLegs ( List< ? extends Animal > animals ) { int retVal = 0; for ( Animal cur : animals ) { retVal += cur.countLegs( ); } return retVal; } 

使用此签名,您可以执行以下操作:

 List dogs = ...; countLegs( dogs ); List cats = ...; countLegs( cats ); List zoo = ...; countLegs( zoo ); 

但是,如果你声明countLegs是这样的:

 int countLegs ( List< Animal > animals ) 

然后在前面的例子中只有countLegs( zoo )会编译,因为只有那个调用具有正确的类型。

Javagenerics是不变的。

假设我们有B extends A

  • BA的亚型
  • instanceof Binstanceof A也是instanceof Ainstanceof A

由于Java数组是协变的:

  • B[]A[]的子类型
  • instanceof B[]instanceof A[]也是instanceof A[]instanceof A[]

但是,Javagenerics是不变的:

  • List不是List的子类型
  • instanceof Listinstanceof List不是instanceof Listinstanceof List

通配符用于使其更灵活,同时保持类型安全。

  • ListList List

参考

  • Java教程/generics
    • 分型
    • 通配符更有趣

相关问题

  • 任何简单的方法来解释为什么我不能做List animals = new ArrayList()
  • javagenerics(非)协方差
  • 之间有什么区别?

您的两个示例之间的区别仅在于第一个是通用/一般动物的列表 – 因此您可以向其添加任何类型的动物,以及Animal类型的子类的任何实例。 (例如,它可以包含一些狗,一些猫,一些豪猪…)而第二个 – List List – 将是类动物的一个特定子类型的列表。 它可以是您选择的任何一个(每次在运行时设置),但只有一个。 它将是一个狗的列表, 猫的列表, 海龟的列表……等。

您可以将狗和猫存储在List 。 这不是需要通配符的地方。

假设您有一个获取动物列表的方法:

 void foo(List animals) { ... } 

现在你不能传递一个List of Dogs的方法 – 它只需要一个List类型的参数。 您需要一个通配符才能使该方法接受各种动物ListListListList ,…

 void foo(List animals) { ... } 

看到

http://java.sun.com/docs/books/tutorial/extra/generics/wildcards.html