写在前面
JDK5引入了新特性——Java泛型(generics),泛型提供了编译时类型安全检测机制,在程序编译期间可以检查类型安全,实现参数类型的“任意化”。而在没有泛型的情况下,是通过对类型Object的引用来实现参数的“任意化”,这种方法需要显示的强制类型转换,但是强制类型转换错误只有在运行时才会出现异常。
翻译一篇关于比照Set和Set<?>区别的英文文章,原文链接Set vs. Set<?>
翻译原文如下
- 关于Set<?>的两个事实:
第1条:由于通配符?代表的是任意类型,所以Set<?>可以包含任意类型的元素。
第2条:因为不知道?类型,因此不可以放入任意元素。
根据第1条Set<?>可以保存任何类型的元素,可是根据第2条又不能放入任何元素。但是两者却并不发生冲突,通过下面两个例子可以清晰阐述。
第1条意味着下面情形:
//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对象进行操作。
第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<?>初始化一个set。下面的代码片段是非法的:
//Illegal Code
Set<?> set = new HashSet<?>();
- Set vs. Set<?>
那么Set与Set<?>之间的不同是什么呢?
下面定义的方法可以很清楚看出:
public static void printSet(Set s) {
s.add("2");
for (Object o : s) {
System.out.println(o);
}
}
因为Set没有指定类型,对存入的元素没有任何的限制。这就很容易破坏集合的一致性,也就是集合中的元素类型可能不同。
简单而言,通配符?类型是更加安全的,而原生类型是不安全的。我们不可以把任何元素放入到Set<?>中。
- 什么时候使用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;
}
网友评论