为什么这个泛型方法不接受任何类型?

时间:2013-10-30 21:53:25

标签: java generics

在下面的代码中,当我致电getList()时,我无法指定<T>getList<T>()无法编译。

相反,我只能致电getList() - 但<T>始终只是<Event>

为什么会这样?

class Foo
{
    public static void main (String[] args) throws java.lang.Exception
    {
        // For the sake of a complete example - the next method has
        // my question.
        Foo f = new Foo();
        f.register(new Subscriber<MyEvent>() {
            public void handle(MyEvent event){};
        });
    }

    public <T extends Event> void register(Subscriber<T> subscriber) {

        // Below won't work. I can't specify <T>, so getList()
        // will return a HashSet<Subscriber<Event>>, to which I cannot
        // add the Subscriber<T>!

        getList().add(subscriber);

        // Why can't I call getList<T>().add(subscriber) ?

    }

    private <T extends Event> HashSet<Subscriber<T>> getList() {
        // For the sake of example, simply return a new HashSet.
        return new HashSet<Subscriber<T>>();
    }
}

interface Subscriber<T extends Event> {
    public void handle(T event);
}

interface Event { }
class MyEvent implements Event { }

4 个答案:

答案 0 :(得分:1)

似乎Java不会接受<T>作为简单名称(如getList())的类型参数。但是如果你在调用方法时明确说明this.,它会接受它:

this.<T>getList().add(subscriber);

答案 1 :(得分:1)

我认为正确的答案是将Foo变为Foo<T extends Event>,以便在定义Foo T时。

否则,请尝试this.<T>getList()。这是静态MyClass.<String>someMethod()的完成方式。不确定它是否也适用于实例方法。同样,最好的答案是使Foo通用。

答案 2 :(得分:0)

示例中的T正在Event类的两种方法中扩展Foo。那么含蓄地意味着你Foo类仅适用于<T extends Event>类型推断。不幸的是,您的T仅在方法范围内定义。对于人类来说,所有人看起但编译器有点不同。编译器不相信你,也无法找出隐含的信息,但它们在逻辑上也很好。您没有在Class范围中定义T,并且编译器没有发现您在两种方法中都使用相同的类型推断。所以,编译器不会让你把这些方法混合在一起。

因此,解决方案应该明确定义类型推断是针对类范围使用的,不仅仅是方法范围。

class Foo<T extends Event>
{
    public static void main (String[] args) throws java.lang.Exception
    {
        // For the sake of a complete example - the next method has
        // my question.
        Foo<MyEvent> f = new Foo<MyEvent>();
        f.register(new Subscriber<MyEvent>() {
            public void handle(MyEvent event){};
        });
    }

    public void register(Subscriber<T> subscriber) {

        // Below won't work. I can't specify <T>, so getList()
        // will return a HashSet<Subscriber<Event>>, to which I cannot
        // add the Subscriber<T>!

        getList().add(subscriber);

        // Why can't I call getList<T>().add(subscriber) ?

    }

    private HashSet<Subscriber<T>> getList() {
        // For the sake of example, simply return a new HashSet.
        return new HashSet<Subscriber<T>>();
    }

}

interface Subscriber<T extends Event> {
    public void handle(T event);
}

 class MyEvent extends Event {

}
 class Event {

}

答案 3 :(得分:0)

也许你需要对Java更温和一点。这似乎没有任何警告:

HashSet<Subscriber<T>> list = getList();
list.add(subscriber);