通配符 <? extends T> 抛出非静态嵌套的不兼容类型错误 class

Wild card <? extends T> throws incompatible types error for non-static nested class

我已经开始学习泛型,但遇到了一个我不理解的关于通配符的编译错误。

考虑以下链表的部分实现:

public class LinkedList<T> {
    Node<T> head;

    private class Node<T> {
        T item;
        Node<T> next;

        Node(T item){
            this.item = item;
        }
    }

    public void concat(LinkedList<T> otherList) {
        Node<T> otherListHead = otherList.head;
        // ... iterating through otherList and adding its members to this list
    }
}

编译得很好。

但是,如果我希望能够连接任何扩展 T 的通配符列表:

public class LinkedList<T> {
    ...
    public void concat(LinkedList<? extends T> otherList) {
        Node<? extends T> otherListHead = otherList.head;
        // ... iterating through other list and adding its members to this list
    }
}

我会得到以下编译错误:

 error: incompatible types: LinkedList<CAP#1>.Node<CAP#1> cannot be converted to LinkedList<T>.Node<? extends T>
        Node<? extends T> otherListHead = otherList.head;
                                                   ^
  where T is a type-variable:
    T extends Object declared in class LinkedList
  where CAP#1 is a fresh type-variable:
    CAP#1 extends T from capture of ? extends T

现在我有两个问题:

  1. 阅读 the get-put principle and about errors when wrapping wild cards 后,我很清楚为什么它不起作用,但我仍然很乐意得到具体的解释。
  2. 最让我困惑的是,使嵌套 class static 消除了编译错误,但我不明白为什么。
public class LinkedList<T> {
    Node<T> head;

    /*This compiles well. Why?*/
    private static class Node<T> {
        T item;
        Node<T> next;

        Node(T item){
            this.item = item;
        }
    }

    public void concat(LinkedList<? extends T> otherList) {
        Node<? extends T> otherListHead = otherList.head;
        // ... iterating through other list and adding its members to this list
    }
}

如果有人能对此有所启发,我会很高兴,干杯!

问题是编译器不知道 LinkedList<? extends T> 的类型 Node<? extends T> 相同的 类型 - 这两个通配符类型可以是 T 不同 子类型,因此编译错误是适当的。

修复方法是键入 方法,将子类型锁定为相同 子类型:

public <U extends T> void concat(LinkedList<U> otherList) {
    // see below
}

这与通配符<? extends T>相同,但它是方法调用的常量。

您还需要在方法中使用更多的泛型:

public <U extends T>  void concat(LinkedList<U> otherList) {
    // Because you have an inner class, you must use this syntax
    LinkedList<U>.Node<U> otherListHead = otherList.head;
    // Create the local typed Node using the foreign Node's data
    Node<T> node = new Node<>(otherList.head.item);
    // Add node to this and repeat for all Nodes in the other list 
}

当 Node 是静态的 class 时它无需特殊语法即可工作的原因,即:

public <U extends T>  void concat(LinkedList<U> otherList) {
    Node<U> otherListHead = otherList.head; // doesn't need LinkedList<U> prefix
    // ...
}

是因为静态 classes 的实例是独立存在的,而内部 classes 没有封闭的 class 实例就不能存在,这只是 java 需要。

顺带一提,当Nodeclass不是static时,Node的T类型隐藏了LinkedList的T类型,因此您应该从 Node 中删除类型,而不是仅使用 LinkedList 中的类型 T,内部 class Node 从封闭的 LinkedList 实例中获取,即:

public static class LinkedList<T> {
    Node head;

    private class Node { // non static version should not be typed
        T item;  // T comes from the enclosing class instance
        Node next;

        Node(T item){
            this.item = item;
        }
    }
    // ...
}

也许这就是您的意图。