泛型和通配符
使用泛型和通配符都可以让一个方法所表示的算法逻辑适应多种类型。
Java中具备继承关系的类A、B(A extends B
)它们的集合List<A>
和List<B>
之间是没有继承关系的,
可以使用泛型或通配符来让一个方法支持同时接受List<A>
和List<B>
。
代码场景
这里分别定义类Animal、Dog和Cat,很显然,Dog和Cat是Animal的子类。
它们的简单定义如下:
abstract class Animal {
public abstract boolean afraidOf(Animal other);
}
class Cat extends Animal {
@Override
public boolean afraidOf(Animal other) {
if (other instanceof Dog) {
return true;
}
return false;
}
}
class Dog extends Animal {
@Override
public boolean afraidOf(Animal other) {
if (other instanceof Cat) {
return false;
}
return true;
}
}
上面Animal类定义了boolean afraidOf(Animal other)
方法,表示一个动物是否害怕另一个动物。
可以看到Cat和Dog有着不同的表现。
假设有下面需求:
从一个List<Animal>
中找到某个Animal对象害怕的所有其它动物。
对应有以下的API方法:
public List<Animal> findScaredAnimals(List<Animal> animals, Animal who) {
//...
}
如果这时有List<Dog>
或者List<Cat>
这种,也应该是支持的。
可以通过通配符或者泛型方法实现。
通配符实现
使用List<? extends Animal>
这样的形参,就可以接收集合项为Animal子类的任意List。
public List<Animal> findScaredAnimals(List<? extends Animal> animals, Animal who) {
//...
}
这时就可以这样调用了:
List<Dog> dogs;
....
findScaredAnimals(dogs, animal);
...
其他Animal子类的List都是可以的。
泛型方法实现
抛开实际意义,假设需要findScaredAnimals()中,返回值和参数对应的具体Animal子类型是一致的,那么就需要用到泛型了:
public <T extends Animal> List<T> findScaredAnimals(List<T> animals, T who) {
//...
}
可以看到,泛型类型参数T同时约束了多个地方。
泛型参数也可以是多个的,而且之间存在关系。
小结
以上通过一个不太实际的案例说明了使用泛型和通配符来解决List泛型集合之间的“匹配”问题。这也是它们的主要用途之一。
(本文使用Atom编写)