在我的上一个问题(谢谢大家回答我),我已经了解了List<Object>和之间的区别List<?>.
但是我仍然看不到通配符的用处.
我有两个ArrayLists:
ArrayList<Integer> li = new ArrayList<Integer>(Arrays.asList(1,2,3));
ArrayList<String> ls = new ArrayList<String>(Arrays.asList("one","two","three"));
Run Code Online (Sandbox Code Playgroud)
现在,看看下面的两个代码块:
static void printList(ArrayList<?> list)
{
for (Object elem: list)
System.out.print(elem + " ");
System.out.println();
}
Run Code Online (Sandbox Code Playgroud)
和
static <T> void printList(ArrayList<T> list)
{
for (T elem: list)
System.out.print(elem + " ");
System.out.println();
}
Run Code Online (Sandbox Code Playgroud)
我打电话的时候:
printList(li);
printList(ls);
Run Code Online (Sandbox Code Playgroud)
两种方法都返回输出:
1 2 3
one two three
Run Code Online (Sandbox Code Playgroud)
然而第二个解决方案,在for循环中,而不是Objects我使用参数化类型(我认为更优雅).
所以,主要问题仍然存在:为什么我们需要通配符?
Rob*_*tti 11
如果问题是"通配符的用处":
当只需要部分关于类型参数的知识时,通配符很有用."部分知识"由上限和下限实现(?super T或?extends T); 如果你只使用未绑定的通配符(?),那么你根本就没有任何知识,而且你无法看到通配符在哪里真正有用.
通配符可以在具有类型参数的组合中使用,以在方法参数类型,返回类型和异常类型之间创建关系.所以有用的通配符的例子是
class ListManager<T> {
public void add(T item, List<? super T> list) {
[... some useful operation ...]
list.add(item);
}
}
public class Main {
public static void main(String[] args) {
List<Object> list = new ArrayList<Object>();
Integer item = 10;
ListManager<Integer> manager = new ListManager<Integer>();
manager.add(item, list);
}
}
Run Code Online (Sandbox Code Playgroud)
方法"ListManager.add()"在"list"的类型和"item"的类型之间创建关系."list"上的操作总是类型安全的,但是你可以使用方法"add"和不同参数类型的列表:我们在参数"list"上使用了最小约束.
(另见jls7文档)
Collection<?> c = new ArrayList<String>();
c.add(new Object()); // Compile time error
Run Code Online (Sandbox Code Playgroud)
由于我们不知道c的元素类型代表什么,我们无法向其添加对象.add()方法接受类型为E的参数,即集合的元素类型.当实际类型参数为?时,它代表某种未知类型.我们传递给add的任何参数都必须是这种未知类型的子类型.因为我们不知道它是什么类型,所以我们无法传递任何内容.唯一的例外是null,它是每种类型的成员.
另一方面,给定List,我们可以调用get()并使用结果.结果类型是未知类型,但我们始终知道它是一个对象.因此,可以安全地将get()的结果赋给Object类型的变量,或者将其作为期望Object类型的参数传递.
因此,具有通配符类型可确保我们无法add()访问List,除了null.如果您只是在调用get()List,那么您知道它至少是一个Object.
使用通配符,您的代码是类型安全的。在
List myList;
Run Code Online (Sandbox Code Playgroud)
您可以添加任何您想要的对象。但在:
List<?> myList;
Run Code Online (Sandbox Code Playgroud)
您只能添加一个null。
当您需要类 (List.class) 或需要检查类型(List 的实例)时,您应该只使用 List,而不使用类型参数。