泛型方法(有界类型)与继承

jwp*_*pol 1 java generics inheritance

我有一个典型的问题什么更好,我认为答案总是视情况而定,但无论如何我想澄清一下。所以有两种方法:

public static <A extends Animal, F extends Food> void feed(A animal, F food) {
    animal.setFood(food);
}

public static void feed(Animal animal, Food food) {
    animal.setFood(food);
}
Run Code Online (Sandbox Code Playgroud)

和逻辑:

Cat cat = new Cat(); // Cat is a child of Animal
Dog dog = new Dog(); // Dog is a child of Animal

Pork pork = new Pork(); // Pork is a child of Food
pork.setName("Whiskas");
Beef beef = new Beef(); // Beef is a child of Food
beef.setName("Pedigree");

AnimalService.feed(cat, beef);
AnimalService.feed(dog, pork);

cat.eat(); // prints I'm eating Pedigree
dog.eat(); // prints I'm eating Whiskas
Run Code Online (Sandbox Code Playgroud)

我知道由于类型擦除而存在方法签名冲突,所以我的问题不是“为什么我不能同时使用这两种方法?”,而是“你会选择哪种方法?”。

Tho*_*mas 5

正如你所说,这取决于。您需要记住,泛型是一种编译时工具,可以帮助编译器进行一些检查,并在违反约束时吐出错误。

Animal在您的情况下,除了参数类型(和)的上限之外,您似乎没有任何要违反的约束,Food因此您不会从使用泛型中获得任何好处 - 因此我会选择基于普通继承的方法。

但是,考虑一下您正在更改Animal接口来定义动物所需的食物种类(从而添加继承无法帮助您在编译时强制执行的约束):

interface Animal<F extends Food> { ... }

class DogFood implements Food { ... }
class CatFood implements Food { ... }
class Whiskas extends CatFood { ... }

class Dog implements Animal<DogFood> { ... }
class Cat implements Animal<CatFood> { ... }
Run Code Online (Sandbox Code Playgroud)

现在feed()可以使用泛型让编译器帮助您选择正确的食物类型:

<F extends Food> void feed(Animal<F> animal, F food) { ... }

//this should compile because Cat defines Food needs to be CatFood
feed(new Cat(), new CatFood());

//this should also compile because Whiskas is CatFood
feed(new Cat(), new Whiskas());

//this shouldn't compile because DogFood is not CatFood
feed(new Cat(), new DogFood());
Run Code Online (Sandbox Code Playgroud)