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());
}
这两个方法的名称不能相同,因为它会导致编译时错误。那么这两种方法有什么区别吗?
答案 0 :(得分:6)
两者都这样做,但在第二种情况下,编译器被告知您确实需要一个没有类型边界的列表并且不会引发警告。如果您使用的是Java 5或更高版本,则鼓励您使用第二种方法。
答案 1 :(得分:1)
不同之处在于您无法向List<?>
添加任何内容,因为它是未知类型的列表。
例如,您无法执行此操作:
List<Integer> listOfInt = new ArrayList<Integer>();
List<?> list = listOfInt;
list.add("hello?"); // Compile-time error
您可以将任何内容添加到基本类型List
,因为未检查列表项的类型。
答案 2 :(得分:1)
List<?>
(发音为“collection of unknown”)是一个元素类型与任何东西匹配的集合。由于显而易见的原因,它被称为通配符类型。
请参阅以下代码
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,它是每种类型的成员。
另一方面,给定List<?>
,我们可以调用get()并使用结果。结果类型是未知类型,但我们始终知道它是一个对象。因此,可以安全地将get()的结果赋给Object类型的变量,或者将其作为期望Object类型的参数传递。
答案 3 :(得分:0)
第二种方法使用泛型(在Java 5中引入)。
一个重要的区别是<?>
代表一种类型,而不是像这样的任何对象:
List<? extends Object> myList
所以你可以说使用第一种方法(没有通配符语法)更灵活,因为你可以将任何对象添加到List中。虽然,你会得到一个(编译器)警告声明你应该参数化。
使用<?>
无界通配符语法将避免警告,但是您告诉编译器它可以是任何类型的列表,而不是实际使用泛型来强制类型安全。强烈建议您使用泛型来帮助您确保应用程序类型的安全。
例如,如果你知道列表应该只包含String对象,那么声明它:
List<String> myList
然后,您将避免不必要地使用instanceof
运算符等
以下是Java中泛型的简要教程,供您参考:
http://javarevisited.blogspot.co.uk/2011/09/generics-java-example-tutorial.html
答案 4 :(得分:0)
列表是原始类型和列表&lt; ?&GT;是通配符类型。看看http://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html
答案 5 :(得分:0)
他们两个都表现相同。使用参数化表示法,您只需避免Java5及更高版本中的任何警告。你不能在同一个java文件中同时拥有这两种语法,因为由于类型擦除,编译单元有两个方法在同一个类文件中具有完全相同的签名,因此违反了语言规则。 以下是您将从编译器获得的内容:
方法processList(List)与类型中的另一种方法具有相同的擦除processList(List)...
答案 6 :(得分:0)
不建议在没有类型参数的情况下编写List
,但与编写List<Object>
相同。所以问题变成“List<Object>
和List<?>
之间有什么区别?我应该使用哪一个?”。
如您所知,您无法向null
添加(List<?>
以外的任何内容),因此如果您需要添加到列表,则应使用List<Object>
(当然,或者适用的更具体类型)。另一方面,采用List<Object>
的方法只接受List<Object>
,而不接受包含Object
子类的任何列表。也就是说,它不会接受List<String>
。但是,如果该方法采用List<?>
,则它接受任何类型的列表。因此,如果您不需要添加到列表中,则应使用List<?>
,因为它更为通用。