Set和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.









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值