翻譯自: Set vs. Set<?>
你可能知道一個無界的通配符Set <?>可以容納任何類型的元素,而一個原始類型Set也可以容納任何類型的元素。 但是他們有什麼區別呢?
1.Set<?>的兩個事實
(1)由於問號? 代表任何類型,所以 Set <?>能夠容納任何類型的元素;
(2)因爲我們不知道?的類型,所以我們不能把任何元素放入Set <?>中
所以一個Set <?>可以容納任何類型的元素(Item 1),但是我們不能放入任何元素(Item 2)。 這兩個說法是不是就相互衝突了? 當然,他們並不衝突。 這可以通過以下兩個例子清楚地說明:
第一個例子:
//Legal Code
public static void main(String[] args) {
HashSet<Integer> s1 = new HashSet<Integer>(Arrays.asList(1, 2, 3));
printSet(s1);
HashSet<String> s2 = new HashSet<String>(Arrays.asList("a", "b", "c"));
printSet(s2);
}
public static void printSet(Set<?> s) {
for (Object o : s) {
System.out.println(o);
}
}
由於Set <?>可以容納任何類型的元素,我們只需在循環中使用Object(因爲Object是所有類的父類)。
第二種不合法的情況:
//Illegal Code
public static void printSet(Set<?> s) {
s.add(10);//this line is illegal
for (Object o : s) {
System.out.println(o);
}
}
因爲我們完全不知道 ? 的類型,除了null之外,我們不能添加任何東西。 出於同樣的原因,我們不能用Set <?>初始化一個集合。 下面的這個操作是非法的:
//Illegal Code
Set<?> set = new HashSet<?>(); // compile error:Cannot instantiate the type HashSet<?>
2. Set vs. Set<?>
原始類型Set和無界通配符Set <?>有什麼區別?這個方法聲明得很好:
public static void printSet(Set s) {
s.add("2");
for (Object o : s) {
System.out.println(o);
}
}
因爲原始類型沒有添加限制。 但是,這很容易破壞集合的不變性,簡單的說,通配符類型是安全的,原始類型不是。 我們不能把任何元素放入Set <?>中。
3.Set<?>在什麼時候用?
當你想使用一個泛型類型,但是你不知道或不關心參數是什麼類型時,你可以使用<?> (參考:Bloch, Joshua. Effective java. Addison-Wesley Professional, 2008.), 它只能用作方法的參數。
例如:
public static void main(String[] args) {
HashSet<Integer> s1 = new HashSet<Integer>(Arrays.asList(1,2,3));
HashSet<Integer> s2 = new HashSet<Integer>(Arrays.asList(4,2,3));
System.out.println(getUnion(s1, s2));
}
public static int getUnion(Set<?> s1, Set<?> s2){
int count = s1.size();
for(Object o : s2){
if(!s1.contains(o)){
count++;
}
}
return count;
}