让我们首先考虑一个简单的场景(请参阅ideone.com上的完整源代码):
import java.util.*;
public class TwoListsOfUnknowns {
static void doNothing(List<?> list1, List<?> list2) { }
public static void main(String[] args) {
List<String> list1 = null;
List<Integer> list2 = null;
doNothing(list1, list2); // compiles fine!
}
}
Run Code Online (Sandbox Code Playgroud)
这两个通配符是不相关的,这就是为什么你可以doNothing用a List<String>和a 调用List<Integer>.换句话说,两者?可以指代完全不同的类型.因此,以下不编译,这是预期的(也在ideone.com上):
import java.util.*;
public class TwoListsOfUnknowns2 {
static void doSomethingIllegal(List<?> list1, List<?> list2) {
list1.addAll(list2); // DOES NOT COMPILE!!!
// The method addAll(Collection<? extends capture#1-of ?>)
// in the type List<capture#1-of …Run Code Online (Sandbox Code Playgroud) 为什么java中我们做不到:
List<List<? extends Number>> aList = new ArrayList<List<Number>>();
Run Code Online (Sandbox Code Playgroud)
即使这样也可以:
List<? extends Number> aList = new ArrayList<Number>();
Run Code Online (Sandbox Code Playgroud)
编译器错误消息是:
Type mismatch: cannot convert from ArrayList<List<Number>> to List<List<? extends Number>>
这个方法声明有什么区别:
public static <E extends Number> List<E> process(List<E> nums){
Run Code Online (Sandbox Code Playgroud)
和
public static List<Number> process(List<Number> nums){
Run Code Online (Sandbox Code Playgroud)
你会在哪里使用前者?
我知道为什么不应该这样做.但有没有办法向外行人解释为什么这是不可能的.你可以轻松地向外行解释:Animal animal = new Dog();.狗是一种动物,但是一系列的狗并不是动物的清单.
这可以返回一个int列表:
public List<Integer> GetIListImpl() {
return new ArrayList<Integer>();
}
Run Code Online (Sandbox Code Playgroud)
但是,如果我想让调用者指定泛型类型呢?像这样的东西,虽然从语法上来说我不知道怎么做:
public List<T> GetIListImpl<T>() {
return new ArrayList<T>();
}
Run Code Online (Sandbox Code Playgroud)
用法是:
List<String> = GetIListImpl<String>();
Run Code Online (Sandbox Code Playgroud) 在Java中我可以演员:
List<?> j = null;
List<Integer> j2 = (List<Integer>)j;
Run Code Online (Sandbox Code Playgroud)
那么为什么以下失败呢?
List<List<?>> i = null;
List<List<Integer>> i2 = (List<List<Integer>>)i;
Run Code Online (Sandbox Code Playgroud) 我有一个功能
public static void bar (final List<List<?>> list)
{
}
Run Code Online (Sandbox Code Playgroud)
我可以使用通配符调用(<?>)
bar(new ArrayList<List<?>>());
Run Code Online (Sandbox Code Playgroud)
但不是与其他类型(例如String)
// The method bar(List<List<?>>) in the type Foo is not
// applicable for the arguments (ArrayList<List<String>>)
bar(new ArrayList<List<String>>());
Run Code Online (Sandbox Code Playgroud)
然而,这适用于类似的功能
public static void foo(List<?> l)
{
}
public static void main(String[] args)
{
// no error
foo(new ArrayList<String>());
}
Run Code Online (Sandbox Code Playgroud)
你能解释一下,为什么编译器会在第一种情况下抱怨而不是在第二种情况下抱怨?
我大大简化了我的问题.这是它的读法.
我试图弄清楚为什么以下代码无法编译:
List<AnonType<AnonType<?>>> l = new ArrayList<AnonType<AnonType<?>>>();
l.add( new AnonType<AnonType<String>>() );
Run Code Online (Sandbox Code Playgroud)
哪里
public class AnonType<T> {
T a;
List<T> b;
}
Run Code Online (Sandbox Code Playgroud)
编译器错误表示add不适用于给定的参数.OTOH,以下代码只有1级嵌套通配符完美编译:
List<AnonType<?>> l = new ArrayList<AnonType<?>>();
l.add( new AnonType<String>() );
Run Code Online (Sandbox Code Playgroud) 我有一个带有以下签名的方法:
public <T> int numberOfValues(Map<T, Set<?>> map)
Run Code Online (Sandbox Code Playgroud)
但是我不能称之为传递Map<String, Set<String>>.例如,以下内容无法编译:
Map<String, Set<String>> map = new HashMap<>();
numberOfValues(map);
Run Code Online (Sandbox Code Playgroud)
错误消息是:
numberOfValues (java.util.Map<java.lang.String,java.util.Set<?>>) in class cannot be applied to (java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)
Run Code Online (Sandbox Code Playgroud)
但是,如果我改为以下一切都很好:
public <T, V> int numberOfValues(Map<T, Set<V>> map)
Run Code Online (Sandbox Code Playgroud)
但是我对此并不感兴趣V,因为我只想知道每组的大小.
为了完整起见,这是整个方法:
public <T, V> int numberOfValues(Map<T, Set<V>> map) {
int n = 0;
for (T key : map.keySet()) {
n += map.get(key).size();
}
return n;
}
Run Code Online (Sandbox Code Playgroud)
我知道它也可以像这样完成,但不是问题的重点:)
public <T> int numberOfValues(Map<?, Set<T>> map) {
int n = 0;
for (Set<T> value …Run Code Online (Sandbox Code Playgroud) 我有一个HashMap,其值是ArrayLists,我正在尝试编写一个函数来接受这些HashMaps的泛型实例
HashMap<String, ArrayList<Integer>> myMap = new HashMap<String, ArrayList<Integer>>();
public static void foo(HashMap<?, ArrayList<?>> a) {}
public static void bar(HashMap<?, ? extends ArrayList<?>> a) {}
// Compilation Failure!
foo(myMap);
// This works, but why do I need ? extends ArrayList
bar(myMap)
Run Code Online (Sandbox Code Playgroud)
错误消息是
foo(HashMap<?,ArrayList<?>>)类型中的方法Example不适用于arguments(HashMap<String,ArrayList<Integer>>).
为什么我需要为extends ArrayList使用通配符?
我认为通过拥有ArrayList<?>(没有? extends),我可以将函数限制为仅具有ArrayList值的HashMaps.
我也知道以下通用方法有效:
public static <K,V> void printer(HashMap<K, ArrayList<V>> list) { }
Run Code Online (Sandbox Code Playgroud)
这表现我的想法ArrayList<?>会起作用.有人能解释这里的细微之处吗?
我想使用带有各种列表的地图作为值:
Map<String, List<Integer>> ml;
Map<String, ?> ml2 = ml; // OK
Map<String, List<?>> ml3 = ml; // Type mismatch
Run Code Online (Sandbox Code Playgroud)
为什么最后一行无效?