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

2022-09-01 13:53:24

直到几天前,我才听说过wildcars,在读了我老师的Java书之后,我仍然不确定它的用途以及为什么我需要使用它。

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

List<Animal> listAnimals

相反,我的同事们建议这样:

List<? extends Animal> listAnimals

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

假设我需要一个 get/set 方法,我应该使用前者还是后者?它们有何不同?


答案 1

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

想象一下,你有一个方法:

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

   return retVal;
}

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

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

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

List<Animal> zoo = ...;
countLegs( zoo );

但是,如果您像这样声明:countLegs

int countLegs ( List< Animal > animals )

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


答案 2

Java泛型是不变的。

假设我们有:B extends A

  • B是 的子类型A
  • 一个也是一个instanceof Binstanceof 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>

引用

相关问题


推荐