通配符背后的目的是什么?它们与generics有何不同?
我几天前从未听说过野猫,在读完老师的Java书之后,我仍然不确定它是什么,为什么我需要使用它。
假设我有一个超级Animal
和几个子类,如Dog
, Cat
, Parrot
等……现在我需要有一个动物列表,我的第一个想法是这样的:
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
:
-
B
是A
的亚型 -
instanceof B
的instanceof A
也是instanceof A
的instanceof A
由于Java数组是协变的:
-
B[]
是A[]
的子类型 -
instanceof B[]
的instanceof A[]
也是instanceof A[]
的instanceof A[]
但是,Javagenerics是不变的:
通配符用于使其更灵活,同时保持类型安全。
-
List
是List extends A>
List extends A>
参考
- Java教程/generics
- 分型
- 通配符更有趣
相关问题
- 任何简单的方法来解释为什么我不能做
List
?animals = new ArrayList () - javagenerics(非)协方差
-
和
之间有什么区别?
您的两个示例之间的区别仅在于第一个是通用/一般动物的列表 – 因此您可以向其添加任何类型的动物,以及Animal类型的子类的任何实例。 (例如,它可以包含一些狗,一些猫,一些豪猪…)而第二个 – List extends Animal>
List extends Animal>
– 将是类动物的一个特定子类型的列表。 它可以是您选择的任何一个(每次在运行时设置),但只有一个。 它将是一个狗的列表, 或猫的列表, 或海龟的列表……等。
您可以将狗和猫存储在List
。 这不是需要通配符的地方。
假设您有一个获取动物列表的方法:
void foo(List animals) { ... }
现在你不能传递一个List of Dogs的方法 – 它只需要一个List
类型的参数。 您需要一个通配符才能使该方法接受各种动物List
: List
, List
, List
,…
void foo(List extends Animal> animals) { ... }
看到
http://java.sun.com/docs/books/tutorial/extra/generics/wildcards.html