如何在Java中调用通配符类型的泛型方法?

时间:2015-07-31 13:11:14

标签: java generics wildcard

我发现我无法调用通配符类型的通用方法而且不明白为什么?

public class GenericsTry2 {

    public static class Element {

        private Container<? extends Element> container;

        public Container<? extends Element> getContainer() {
            return container;
        }

        public void setContainer(Container<? extends Element> container) {
            this.container = container;
        }

        public  void doStuff() {
            getContainer().doStuff(this); // how to call this?
        }
    }

    public static class SomeSubElement extends Element {
    }

    public static class SomeSubElement2 extends Element {
    }

    public static class Container<E extends Element> {

        public void doStuff(E element) {
        }

    }

    public static void main(String[] args) {

        Container<SomeSubElement2> c = new Container<SomeSubElement2>();

        Element e = new SomeSubElement();

        c.doStuff((SomeSubElement2) e); // still can do this at compile time this way

    }


}

3 个答案:

答案 0 :(得分:9)

Container<? extends Element>表示the Container can only produce Element(s), but cannot consume Element(s)

原因是? extends Element表示未知子类型Element的整个系列。我们假设您将容器设置为Container<SomeSubElement>。然后,将this传递给容器(即使您知道它是Element或子类型Element)也不正确,因为this可能是或可能不是SomeSubElement(取决于运行时类型)。

在泛型世界中,这称为协方差。

为了编译代码(我不保证你需要这个),你可以这样做(注意我已经将容器改为Element(s)的消费者,而不是制作人):

public class Element {

    private Container<? super Element> container;

    public Container<? super Element> getContainer() {
        return container;
    }

    public void setContainer(Container<? super Element> container) {
        this.container = container;
    }

    public  void doStuff() {
        getContainer().doStuff(this);
    }
}

但是,如果您需要Container同时成为制作人和消费者,只需删除通配符并仅使用<Element>对其进行参数化。

答案 1 :(得分:1)

Container<E extends Element>表示它包含从E延伸的Element内容。不一定是Element本身。

想象一下,如果你有这样的话会发生什么:

Container<RedElement> redElements = new Container<RedElement>();
Container<E extends Element> container = redElements;

// According to your logic it will work
container.add(new Element());

// Problem here. You just put Element there which is not RedElement.
RedElement element = container.getFirst();

答案 2 :(得分:0)

getContainer()方法保证返回扩展Element的类的某个对象。因此编译器此时不知道返回的值实际上是Container类型。如果您要调用doStuff() - Container类的方法,则必须明确地将getContainer()的结果投射到类型Container

((Container) getContainer()).doStuff(this);