6

List和 和有什么不一样List<?>?我知道我不能向List<?>. 我有一个代码:

List<String> myList = new ArrayList<String>();
processList(myList);
processListGeneric(myList);

public static void processList(List myList) {
Iterator it = myList.iterator();
while(it.hasNext())
    System.out.println(it.next());
}

public static void processListGeneric(List<?> myList) {
    Iterator<?> it = myList.iterator();
    while(it.hasNext())
        System.out.println(it.next());
}

这两个方法的名称不能相同,因为它会导致编译时错误。那么这两种方法有什么区别吗?

4

7 回答 7

6

两者都做同样的事情,但在第二种情况下,编译器被告知您确实想要一个没有类型界限的列表并且不会引发任何警告。如果您使用的是 Java 5 或更高版本,我们鼓励您使用第二种方法。

于 2013-06-04T10:07:37.387 回答
1

List<?>(读作“未知集合”)是一个元素类型匹配任何东西的集合。出于显而易见的原因,它被称为通配符类型。参考以下代码

List<String> myList = new ArrayList<String>();
myList.add("John");
String name = myList.get(0);
System.out.println(name); //print John
List<?> myListNew = myList;
myListNew.add("Sam");//Compile time error
String nameNew = myListNew.get(0);//Compile time error
Object newName = myListNew.get(0);
System.out.println(newName);//Prints John

因为我们不知道myListNew的元素类型代表什么,所以我们不能向它添加对象。add() 方法接受类型 E 的参数,即集合的元素类型。当实际类型参数为 ? 时,它代表某种未知类型。我们传递给 add 的任何参数都必须是这种未知类型的子类型。因为我们不知道那是什么类型,所以我们不能传入任何东西。唯一的例外是 null,它是每个类型的成员。

另一方面,给定 a List<?>,我们可以调用 get() 并使用结果。结果类型是未知类型,但我们始终知道它是一个对象。因此,将 get() 的结果分配给 Object 类型的变量或将其作为参数传递给期望为 Object 类型的变量是安全的。

于 2013-06-04T10:30:36.263 回答
1

不同之处在于您不能向 a 添加任何内容List<?>,因为它是一个未知类型的 List。

例如,您不能这样做:

List<Integer> listOfInt = new ArrayList<Integer>();
List<?> list = listOfInt;
list.add("hello?"); // Compile-time error

您可以将任何您想要的内容添加到基本类型List,因为未检查列表项的类型。

于 2013-06-04T10:06:56.053 回答
0

不推荐只写List没有类型参数,但在其他方面与 write 相同List<Object>List<Object>所以问题变成了“我应该使用哪个和哪个有什么区别List<?>?”。

如您所知,您不能将(除 之外的任何内容null)添加到 aList<?>中,因此如果您需要添加到列表中,则应使用 a List<Object>(当然,在适用的情况下使用更具体的类型)。另一方面,采用 a 的方法List<Object>只接受List<Object>s 而不是任何包含 的子类的列表Object。也就是说,它不会接受List<String>. 但是,如果该方法采用 a List<?>,则它接受任何类型的列表。所以如果你不需要添加到列表中,你应该使用它,List<?>因为它更通用。

于 2013-06-04T10:33:56.703 回答
0

第二种方法使用泛型(Java 5 中引入)。

一个重要的区别是<?>表示单一类型,而不是像这样的任何对象:

List<? extends Object> myList

所以你可以说使用第一种方法(没有通配符语法)更灵活,因为你可以将任何对象添加到你的列表中。虽然,你会得到一个(编译器)警告,你的声明应该被参数化。

使用<?>无界通配符语法将避免警告,但您告诉编译器它可以是任何类型的列表,而不是实际使用泛型来强制类型安全。强烈建议您使用泛型来帮助您确保应用程序类型安全。

例如,如果您知道列表应该只包含 String 对象,请这样声明:

List<String> myList

然后,您将避免不必要地使用instanceof运算符等。

这里有一个关于 Java 泛型的简短教程,供您参考:

http://javarevisited.blogspot.co.uk/2011/09/generics-java-example-tutorial.html

于 2013-06-04T10:09:04.297 回答
0

List 是原始类型,List< ?> 是通配符类型。看看http://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html

于 2013-06-04T10:13:50.430 回答
0

两者的行为相同。使用参数化表示法,您只是避免了 Java5 及更高版本中的任何警告。您不能在同一个 java 文件中同时拥有这两种语法,因为由于类型擦除,编译单元在同一个类文件中有两个签名完全相同的方法,因此违反了语言规则。以下是您将从编译器中获得的内容:

方法 processList(List) 与 type 中的另一个方法具有相同的擦除 processList(List) ...

于 2013-06-04T10:15:00.153 回答