你可能知道无界的通配符Set<?>能持有任何类型的元素,一个原生类型Set集合也能持有任何类型的元素,那么他们的不同体现在哪些方面呢?
关于Set<?>的两个事实:
关于Set<?>的两个事实:
1、因为“?”标记可以代表任何类型,Set<?>可以持有任何类型的元素
2、由于不知道“?”代表的类型,所有我们不能把任何元素放到Set<?>集合中
所以Set<?>集合可以持有任何类型的元素(来自事实1),但是我们不能把任何元素加入到其中(事实2)。这两个表示是否彼此相互冲突呢?当然不冲突。通过以下两个例子可以清晰的说明原因:
事实1可以通过下面的例子来说明:
//Legal Code
public static void main(String[] args) {
HashSet<Integer> s1 = new HashSet<Integer>(Arrays.asList(1, 2, 3));
printSet(s1);
}
public static void printSet(Set<?> s) {
for (Object o : s) {
System.out.println(o);
}
}
因为Set<?>可以持有任何类型的元素,所有我们可以用基类Object遍历集合
事实2可以通过下面的例子来说明:
//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<?>();
Set和Set<?>对比
原生类型Set集合(raw type)和无边界通配符类型的集合(unbounded wildcard)的区别在哪里呢?
下面的例子正好用来说明这个问题:
public static void printSet(Set s) {
s.add("2");
for (Object o : s) {
System.out.println(o);
}
}
由于原生类型没有限制,因此,能很容易的将不变的集合加入到集合中
简而言之, 无边界通配符类型的集合是安全的,而原生类型Set集合是不安全的. 我们不能将任何元素放到Set<?>中
那么
Set<?>的作用是什么呢?
当你想要使用泛型,并且不关心参数的实际类型,你可将<?>仅仅当做参数来使用【1】。
例如:
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;
}
参考:
1. Bloch, Joshua. Effective java. Addison-Wesley Professional, 2008.