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

Ric*_*ral 27 java generics wildcard

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

比方说,我有一个超类Animal和几个子类,如Dog,Cat,Parrot,等...现在我需要有动物名单,我首先想到的会是这样的:

List<Animal> listAnimals
Run Code Online (Sandbox Code Playgroud)

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

List<? extends Animal> listAnimals
Run Code Online (Sandbox Code Playgroud)

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

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

Ale*_*yak 24

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

想象一下你有一个方法:

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

   return retVal;
}
Run Code Online (Sandbox Code Playgroud)

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

List<Dog> dogs = ...;
countLegs( dogs );

List<Cat> cats = ...;
countLegs( cats );

List<Animal> zoo = ...;
countLegs( zoo );
Run Code Online (Sandbox Code Playgroud)

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

int countLegs ( List< Animal > animals )
Run Code Online (Sandbox Code Playgroud)

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


pol*_*nts 22

Java泛型是不变的.

假设我们有B extends A:

  • B 是一个子类型 A
  • 一个instanceof B也是一个instanceof A

由于Java数组是协变的:

  • B[] 是一个子类型 A[]
  • 一个instanceof B[]也是一个instanceof A[]

但是,Java泛型是不变的:

  • List<B> 不是的子类型 List<A>
  • a instanceof List<B>不是instanceof List<A>.

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

  • a List<B>是一个List<? extends A>

参考

相关问题


fro*_*die 9

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