You cannot do it with generics.
Imagine that the code you wrote compiled. Then doing this would make no sense
Person person = new Man();
person.eat(new Steak()); //where Steak is a subclass of Food
Now what method should be called? Person defines only a method eat
that has Fruit
parameter.
Generics provide compile-time type safety so they are explicited during compilation. This is called erasure procedure. The compiler will remove all the type parameters and add some casts when necessary.
This method defined in Person
<T extends Food> void eat(T food);
will become when compiled
void eat(Food food);
So if you implement Man like the way you did there will be two methods in Person called eat that have different parameters so they are different methods.
void eat(Food food);
void eat(Fruit food);
One way to do this is to move the generic to class level like this
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);
But this will not compile.
Person<Fruit> person = new Man();
Food food = new Fruit();
person.eat(food); //food must be casted to Fruit
That because when you declare person
the <Fruit>
instructs the compiler to check that you are effectively passing a Fruit
instance. It knows at compile time that you are passing the supertype Food
instead of Fruit
which can lead to cast exceptions on runtime if the code gets compiled in this state, breaking type safety which is what generics are all about. In fact
public class Man implements Person<Fruit> {
public void eat(Fruit fruit) {
System.out.println(fruit.toString());
}
}
Will be compiled like this
public class Man implements Person {
public void eat(Food fruit) {
//The compiler will automatically add the type cast!
System.out.println(((Fruit) fruit).toString());
}
}
One way to bypass compiler type safety checking is to omit generic like this
//This will compile with a warning
//Unchecked use of 'eat(T)' method
((Person)person).eat(food);