我正在寻找一个允许我添加 Deques
的解决方案我的 List
的任何内部类型.
现在下面的代码是可能的。
/*
* Please ignore the missing instantiations. It's only a technical
* precompiler demonstration.
*/
final Deque<String> concreteDeque = null;
final Deque<?> unclearDeque = null;
final List<Deque<?>> list = null;
/*
* The precompiler demands a parameter of type Deque<?>. That means any
* Deque. Great! :)
*/
list.add(concreteDeque); // no precompiler error
list.add(unclearDeque); // no precompiler error
final Deque<?> deque = list.get(0); // no precompiler error, great! :)
现在,我想制作自己的更具体的界面。
/**
* A list that holds instances of {@link Deque}. Only for demonstrations.
*
* @author Barock
*
* @param <DT>
* The type that should pass to the {@link Deque}.
*/
public interface DequeList<DT> extends List<Deque<DT>> { }
但是有了这个接口(interface),我的代码就不能再工作了。
final Deque<String> concreteDeque = null;
final Deque<?> unclearDeque = null;
final DequeList<?> dequeList = null;
// Now the precompiler announces wildcard capture for adding elements!?
dequeList.add(concreteDeque); // precompiler error
dequeList.add(unclearDeque); // precompiler error
final Deque<?> deque = dequeList.get(0); // still no precompiler error. :)
我假设我的 DequeList<?>
相当于 List<Deque<?>>
.为什么显然不是?
最佳答案
List<?>
和 List<List<?>>
之间存在差异(您可以放置任何通用集合来代替列表)。
List<?>
专为只读目的而设计。假设 List<?>
已经包含了一个“some-type”的元素。由于“some-type”过于笼统,你无法确定它是什么类型,因此你不能简单地添加任何东西,因为类型安全,否则列表将包含异构元素(不同类型).
考虑以下示例:
List<String> someLetters = Arrays.asList("a", "b", "c", "d", "e");
List<Integer> someInts = Arrays.asList(1, 2, 3, 4, 5);
displayContent(someLetters);
displayContent(someInts);
public static void displayContent(List<?> list) {
System.out.println(list);
}
当此列表转换为 Integer
时,在 someLetters
中添加 List<?>
是否合法?也许在其他一些语言中这是可能的,但在 Java 中不行,因为指定类型的 Collection
必须是同质的。注意 <?>
指定了隐藏的“some-type”,但它绝对不意味着你可以添加任何你想要的东西。在上面的示例中,方法 displayContent
不知道列表的真实类型,因此任何添加都是非法的:
public static void displayContent(List<?> list) {
// illegal as it may break list's homogenity...
list.add(1);
// illegal as it may break list's homogenity...
list.add("f");
System.out.println(list);
}
在 List<List<?>>
的情况下,你有一个由只读列表组成的列表,它允许你添加任何你想要的只读列表,但不允许你在从这个“列表列表”获得的列表中添加一些东西,也就是说,你可以'出于上述原因,执行类似 list.get(0).add(something);
的操作。
编辑
我不知道为什么 DequeList<?>
不等同于 List<Deque<E>
,但是我刚刚发现了另一件事,这可能对其他试图解决这个谜团的人有用。由于某种原因,您不能添加某种类型 i 的双端队列。 e. Deque<?>
in DequeList<?>
,但是你可以添加没有类型 i 的双端队列。 e. Deque
中的 DequeList<?>
:
Deque<String> concreteDeque = null;
Deque<?> unclearDeque = null;
Deque rawDeque = null;
List<Deque<?>> list = null;
list.add(concreteDeque); // OK
list.add(unclearDeque); // OK
list.add(rawDeque); // OK
DequeList<?> myList = null; // should be equivalent to List<Deque<?>>
myList.add(concreteDeque); // ERROR
myList.add(unclearDeque); // ERROR
myList.add(rawDeque); // OK
似乎在“扩展”之后 Deque<?>
变成了 DequeList
的强类型。由于 DequeList
可能包含特定类型 e 的双端队列。 G。 Deque<String>
,您不能添加 Deque
中指定或隐藏的任何其他类型的 <?>
。不幸的是,它没有回答为什么可以添加 rawDeque
。
关于Java 通配符未按预期通过继承传递(意外的通配符捕获),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47811964/