有界通配符和向队列添加新元素

Bounded wildcards and adding new elements to a queue

前几天我很难理解与有界通配符相关的特定教科书示例以及它们如何与队列结合使用。

该示例首先设置一个简单的继承层次结构:

class X {
    int i;
    X(int i) { this.i = i; }
}

class Y extends X {
    int i;
    Y(int i){ this.i = i; }
}

class Z extends Y {
    int i;
    Z(int i) { this.i = i; }
}

主要 class 托管一个静态方法,该方法采用具有上限通配符定义的 Queue 并添加随机数量的新元素。

public class Wildcards {

    static void rtn(Queue<? extends Y> q) {
        q.add(new Y(5));
        q.add(new Z(5));
    }

    public static void main(String[] args) {
        Queue<Y> q = new LinkedList<>();
        rtn(q);
    }
}

我对这个特定通配符定义的理解是“允许向 q 添加 Y 类型或从 Y 类型扩展的元素。因此 q.add(new Y(5))q.add(new Z(5)). 然而,编译器在 两种 情况下都在抱怨:Required type: capture of ? extends Y - Provided Y/Z.

在这种情况下,我很难理解这条消息 - 我有一种预感,它可能与通配符定义根本无关,但我不确定。

非常感谢您的帮助!

好的,所以首先,您的 class 层次结构已损坏 - 这将无法编译。请记住,基数 class 会变成派生 class 的 "part"。这意味着 a) 你有三个不同的 'i'(每个 class 一个) b) 你没有在你的超级 class 中初始化 i,因为你没有默认构造函数(不带参数)并且您不调用 super(i)。让我们解决这个问题:

class X {
    int i;
    X(int i) { this.i = i; }
}

class Y extends X {
    Y(int i) { super(i); }
}

class Z extends Y {
    Z(int i) { super(i); }
}

现在开始真正的问题:永远记住PECS - 生产者扩展,消费者超级 这意味着,例如,如果您有一个要查询的集合,即在类型安全的情况下从 中获取结果 ,则必须使用带有 extends 的边界。如果你想使用值,例如,将一些东西 放入 集合中,请使用 super.

为什么?所以"super"和"extends"是上下限:

因为 "consumption" <? extends Y> 意味着 "I will only accept classes that Y extends and <? super Y> means "我将只接受 classes 其中 Y 是超级 class".

在你的情况下,你写了一个方法,它应该接受 Queue<Y>Queue<Z> - 所以你说的是 "My methods should accept Queues of Types where Y is the super type"

这会起作用:

public class Wildcards {

    static void rtn(Queue<? super Y> q) {
        q.add(new Y(5));
        q.add(new Z(5));
    }

    public static void main(String[] args) {
        Queue<Y> q = new LinkedList<>();
        rtn(q);
    }
}

https://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html