简体   繁体   English

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

[英]How to call generic method of wildcard type in Java?

I found I can't call generic methods of wildcard types and don't understand why? 我发现我不能调用通配符类型的泛型方法而且不明白为什么?

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

    }


}

Having Container<? extends Element> Container<? extends Element> Container<? extends Element> means that the Container can only produce Element (s), but cannot consume Element (s) . Container<? extends Element>表示Container只能生成 Element ,但不能使用 Element

The reason for this is that ? extends Element 原因是这个? extends Element ? extends Element denotes a whole family of unknown sub-types of Element . ? extends Element表示一系列未知Element子类型。 Let's assume you set your container to Container<SomeSubElement> . 我们假设您将容器设置为Container<SomeSubElement> Then, passing this to the container (even you know it's an Element , or a sub-type of Element ) won't be correct, because this may be or may not be SomeSubElement (depends on the Runtime type). 然后,通过this在容器(即使你知道这是一个Element ,或子类的Element )将不会是正确的,因为this可能会或可能不会SomeSubElement (取决于运行时类型)。

In the world of Generics, this is called co-variance. 在泛型世界中,这被称为协方差。

In order to have the code compiling (I don't guarantee that you need exactly this), you can do (note that I've changed the container to be consumer of Element (s), instead of producer): 为了编译代码(我不保证你需要这个),你可以这样做(注意我已经将容器改为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);
    }
}

However, if you need your Container to be a producer and a consumer at the same time, just get rid of the wildcard and parameterize it with <Element> only. 但是,如果您需要同时将Container作为生产者和消费者,只需删除通配符并仅使用<Element>对其进行参数化。

Container<E extends Element> means that it contains something E that extends from Element . Container<E extends Element>意味着它包含从Element扩展的东西E Not necessarily the Element itself. 不一定是Element本身。

Imagine what would happen if you'll have: 想象一下如果你有以下会发生什么:

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

The getContainer() Method guarantees to return some object of a class that extends Element. getContainer()方法保证返回扩展Element的类的某个对象。 So the compiler does not know at this point that the returned value is actually of type Container . 因此编译器此时不知道返回的值实际上是Container类型。 If you want to call the doStuff() -Method of the Container class, you have to cast the result of getContainer() to the type Container explicitly. 如果要调用Container类的doStuff() Method,则必须将getContainer()的结果显式转换为Container类型。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM