通配符 <? 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
现在我有两个问题:
- 阅读 the get-put principle and about errors when wrapping wild cards 后,我很清楚为什么它不起作用,但我仍然很乐意得到具体的解释。
- 最让我困惑的是,使嵌套 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;
}
}
// ...
}
也许这就是您的意图。
我已经开始学习泛型,但遇到了一个我不理解的关于通配符的编译错误。
考虑以下链表的部分实现:
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
现在我有两个问题:
- 阅读 the get-put principle and about errors when wrapping wild cards 后,我很清楚为什么它不起作用,但我仍然很乐意得到具体的解释。
- 最让我困惑的是,使嵌套 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;
}
}
// ...
}
也许这就是您的意图。