Set 对比 Set<?>
原文地址:http://www.programcreek.com/2013/12/raw-type-set-vs-unbounded-wildcard-set/
您可能知道通配符 Set <?> 可以容纳任何类型的元素,其实原始类型 Set也可以包含任何类型的元素。 两者有什么区别呢?
1. 关于 Set<?> 的两个事实
- 由于
?代表任何类型,所以Set<?>能容纳任何类型的元素 - 因为我们不知道
?是什么类型,所有我们不能将任何元素放入Set<?>
上面两个语句是否相互冲突? 当然不是,我们可以通过以下两个示例来说明:
关于第一点:
//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 即可。
第二点意味着以下情况是非法的:
//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<?>();
2. Set 对比 Set<?>
原始类型 Set 与 通配符 Set<?> 之间到底有什么区别?
下面这个代码是正确的:
public static void printSet(Set s) {
s.add("2");
for (Object o : s) {
System.out.println(o);
}
}
因为原始类型没有限制。 但是,这很容易破坏集合的一致性。
简而言之,通配符类型是安全的,而原始类型不是,并且我们不能将任意元素放入 Set <?> 中。
3. Set<?> 何时是有用的?
当您想使用通用类型,但是你不知道或者不关心参数的实际类型时,可以使用 <?>。注意:它只能用作方法的参数。
举个例子:
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;
}
参考文献
- Bloch, Joshua. Effective java. Addison-Wesley Professional, 2008.