发布
社区首页 >问答首页 >如何使方法返回类型泛型?

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

Stack Overflow用户
提问于 2009-01-16 15:43:09
回答 19查看 809.3K关注 0票数 653

考虑这个例子(在OOP书中很典型):

我有一个Animal类,每个Animal可以有很多朋友。

以及像DogDuckMouse等添加特定行为的子类,如bark()quack()等。

下面是Animal类:

代码语言:javascript
代码运行次数:0
复制
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);
    }
}

下面是一些带有大量类型转换的代码片段:

代码语言:javascript
代码运行次数:0
复制
Mouse jerry = new Mouse();
jerry.addFriend("spike", new Dog());
jerry.addFriend("quacker", new Duck());

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

有没有什么方法可以使用返回类型的泛型来摆脱类型转换,这样我就可以说

代码语言:javascript
代码运行次数:0
复制
jerry.callFriend("spike").bark();
jerry.callFriend("quacker").quack();

下面是一些带有返回类型的初始代码,它作为一个从未使用过的参数传递给该方法。

代码语言:javascript
代码运行次数:0
复制
public<T extends Animal> T callFriend(String name, T unusedTypeObj){
    return (T)friends.get(name);        
}

有没有办法在没有额外参数的情况下使用instanceof计算出运行时的返回类型?或者至少通过传递该类型的类而不是伪实例。

我知道泛型是用于编译时类型检查的,但是有没有解决这个问题的办法呢?

EN

回答 19

Stack Overflow用户

回答已采纳

发布于 2009-01-16 15:57:35

您可以这样定义callFriend

代码语言:javascript
代码运行次数:0
复制
public <T extends Animal> T callFriend(String name, Class<T> type) {
    return type.cast(friends.get(name));
}

然后这样叫它:

代码语言:javascript
代码运行次数:0
复制
jerry.callFriend("spike", Dog.class).bark();
jerry.callFriend("quacker", Duck.class).quack();

这段代码的好处是不会生成任何编译器警告。当然,这实际上只是从前通用时代的转换的更新版本,并没有增加任何额外的安全性。

票数 988
EN

Stack Overflow用户

发布于 2009-01-16 15:50:05

不是的。编译器无法知道jerry.callFriend("spike")将返回什么类型。此外,您的实现只隐藏了方法中的强制转换,而没有任何额外的类型安全性。请考虑以下内容:

代码语言:javascript
代码运行次数:0
复制
jerry.addFriend("quaker", new Duck());
jerry.callFriend("quaker", /* unused */ new Dog()); // dies with illegal cast

在这种特定的情况下,创建一个抽象的talk()方法并在子类中适当地覆盖它会更好地为您服务:

代码语言:javascript
代码运行次数:0
复制
Mouse jerry = new Mouse();
jerry.addFriend("spike", new Dog());
jerry.addFriend("quacker", new Duck());

jerry.callFriend("spike").talk();
jerry.callFriend("quacker").talk();
票数 129
EN

Stack Overflow用户

发布于 2009-01-16 15:51:54

您可以像这样实现它:

代码语言:javascript
代码运行次数:0
复制
@SuppressWarnings("unchecked")
public <T extends Animal> T callFriend(String name) {
    return (T)friends.get(name);
}

(是的,这是法律代码;请参阅Java Generics: Generic type defined as return type only。)

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

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

代码语言:javascript
代码运行次数:0
复制
jerry.<Dog>callFriend("spike").bark();

虽然这可能比强制转换好一点,但正如David Schmitt所说的那样,最好为Animal类提供一个抽象的talk()方法。

票数 127
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/450807

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档