Set 对比 Set<?>

原文地址:http://www.programcreek.com/2013/12/raw-type-set-vs-unbounded-wildcard-set/

您可能知道通配符 Set <?> 可以容纳任何类型的元素,其实原始类型 Set也可以包含任何类型的元素。 两者有什么区别呢?

1. 关于 Set<?> 的两个事实

  1. 由于 ? 代表任何类型,所以 Set<?> 能容纳任何类型的元素
  2. 因为我们不知道 ?是什么类型,所有我们不能将任何元素放入 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;
}

参考文献

  1. Bloch, Joshua. Effective java. Addison-Wesley Professional, 2008.

results matching ""

    No results matching ""