如何使方法返回类型泛型?

2022-08-31 04:08:39

考虑这个例子(在OOP书籍中很常见):

我有一个班级,每个班级都可以有很多朋友。
和子类,如, 等,它们添加特定的行为,如,等等。AnimalAnimalDogDuckMousebark()quack()

下面是类:Animal

public class Animal {
    private Map<String,Animal> friends = new HashMap<>();

    public void addFriend(String name, Animal animal){
        friends.put(name,animal);
    }

    public Animal callFriend(String name){
        return friends.get(name);
    }
}

这里有一些代码片段,其中包含大量的类型转换:

Mouse jerry = new Mouse();
jerry.addFriend("spike", new Dog());
jerry.addFriend("quacker", new Duck());

((Dog) jerry.callFriend("spike")).bark();
((Duck) jerry.callFriend("quacker")).quack();

有没有办法使用泛型作为返回类型来摆脱类型转换,这样我就可以说

jerry.callFriend("spike").bark();
jerry.callFriend("quacker").quack();

下面是一些初始代码,其中返回类型作为从未使用的参数传递给方法。

public<T extends Animal> T callFriend(String name, T unusedTypeObj){
    return (T)friends.get(name);        
}

有没有办法在运行时找出返回类型,而无需使用额外的参数?或者至少通过传递该类型的类而不是虚拟实例。
我知道泛型是用于编译时类型检查的,但是有没有解决方法?instanceof


答案 1

您可以这样定义:callFriend

public <T extends Animal> T callFriend(String name, Class<T> type) {
    return type.cast(friends.get(name));
}

然后这样称呼它:

jerry.callFriend("spike", Dog.class).bark();
jerry.callFriend("quacker", Duck.class).quack();

此代码的优点是不生成任何编译器警告。当然,这实际上只是前通用时代的铸造的更新版本,并没有增加任何额外的安全性。


答案 2

你可以像这样实现它:

@SuppressWarnings("unchecked")
public <T extends Animal> T callFriend(String name) {
    return (T)friends.get(name);
}

(是的,这是法律代码;请参阅 Java 泛型:仅定义为返回类型的泛型类型

返回类型将从调用方推断出来。但是,请注意注释:它告诉您此代码不是类型安全的。您必须自己验证它,否则可以在运行时获得。@SuppressWarningsClassCastExceptions

不幸的是,你使用它的方式(不将返回值分配给临时变量),让编译器满意的唯一方法是这样调用它:

jerry.<Dog>callFriend("spike").bark();

虽然这可能比铸造好一点,但正如David Schmitt所说,你最好给这个类一个抽象的方法。Animaltalk()


推荐