你不能用泛型来做到这一点。
假设您编写的代码已编译。那么这样做就没有意义了
Person person = new Man();
person.eat(new Steak()); //where Steak is a subclass of Food
现在应该调用什么方法? Person 仅定义了一个方法 eat,它具有 Fruit 参数。
泛型提供编译时类型安全,因此它们在编译期间被显式显示。这称为擦除过程。编译器将删除所有类型参数并在必要时添加一些类型转换。
这个方法定义在Person
<T extends Food> void eat(T food);
编译后会变成
void eat(Food food);
因此,如果您像以前那样实现 Man,那么 Person 中将有两个名为 eat 的方法,它们具有不同的参数,因此它们是不同的方法。
void eat(Food food);
void eat(Fruit food);
一种方法是像这样将泛型移动到类级别
public interface Person<T extends Food> {
void eat(T food);
}
//We enforce the Man class to only "eat" Fruit foods.
public class Man implements Person<Fruit> {
public void eat(Fruit fruit) {
//Eat some fruit
}
}
//This will work and compile just fine
Person<Fruit> person = new Man();
Fruit fruit = new Fruit();
person.eat(fruit);
但这不会编译。
Person<Fruit> person = new Man();
Food food = new Fruit();
person.eat(food); //food must be casted to Fruit
那是因为当您声明 person 时,<Fruit> 会指示编译器检查您是否有效地传递了 Fruit 实例。它在编译时知道您传递的是超类型Food 而不是Fruit,如果代码在此状态下编译,这可能会导致运行时出现强制转换异常,从而破坏泛型所涉及的类型安全。其实
public class Man implements Person<Fruit> {
public void eat(Fruit fruit) {
System.out.println(fruit.toString());
}
}
会这样编译
public class Man implements Person {
public void eat(Food fruit) {
//The compiler will automatically add the type cast!
System.out.println(((Fruit) fruit).toString());
}
}
绕过编译器类型安全检查的一种方法是省略这样的泛型
//This will compile with a warning
//Unchecked use of 'eat(T)' method
((Person)person).eat(food);