如何在接口方法中使用泛型类型参数

时间:2020-04-19 23:01:04

标签: java generics

我创建了一个界面:

public interface Person {
    <T extends Food> void eat(T food);
}

其中Food是具体但非最终的class

我想用eat的子类(即Food来实现Person的Fruit方法,像这样:

public class Man implements Person {
    @Override
    public void eat(Fruit food) {
        //implementation here
    }
}

但是有编译错误

问题:为什么会出现编译错误?如何在不向接口public interface Person<T>添加通用类型的情况下解决错误?

2 个答案:

答案 0 :(得分:1)

您不能使用泛型。

想象一下,您编写的代码已编译。那么这样做毫无意义

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); 

答案 1 :(得分:1)

Person接口中eat方法的约定指定该方法适用于Food的子类型的任何类型。当您在Person类中定义仅接受Food实例的另一个方法时,您没有在接口中遵守该方法的约定,因此您不会覆盖它。

正如您提到的,要在使用泛型的类的实现中设置具体类型,该类本身必须是泛型的(您必须在类级别具有泛型类型)。

相关问题