Set vs. Set<?>

简介:

You may know that an unbounded wildcard Set<?> can hold elements of any type, and a raw type Set can also hold elements of any type. What is the difference between them?

Two facts about Set<?>

There are two facts about Set<?>:

  • Item 1: Since the question mark ? stands for any type. Set<?> is capable of holding any type of elements.
  • Item 2: Because we don't know the type of ?, we can't put any element into Set<?>

So a Set<?> can hold any type of element(Item 1), but we can't put any element into it(Item 2). Do the two statements conflict to each other? Of course they are not. This can be clearly illustrated by the following two examples:

Item 1 means the following situation:

//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);
    }
} 

Since Set<?> can hold any type of elements, we simply use Object in the loop.

Item 2 means the following situation which is illegal:

//Illegal Code
public static void printSet(Set<?> s) {
    s.add(10);//this line is illegal 
    for (Object o : s) {
        System.out.println(o);
    }
}

Because we don't know the type of <?> exactly, we can not add any thing to it other than null. For the same reason, we can not initialize a set with Set<?>. The following is illegal:

//Illegal Code
Set<?> set = new HashSet<?>();
Set vs. Set<?>

What's the difference between raw type Set and unbounded wildcard Set<?>?

This method declaration is fine:

public static void printSet(Set s) {
    s.add("2");
    for (Object o : s) {
        System.out.println(o);
    }
}

because raw type has no restrictions. However, this will easily corrupt the invariant of collection.

In brief, wildcard type is safe and the raw type is not. We can not put any element into a Set<?>.

When Set<?> is useful?

When you want to use a generic type, but you don't know or care what the actual type the parameter is, you can use <?>[1]. It can only be used as parameters for a method.

For example:

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;       
}

Reference:

  1. Bloch, Joshua. Effective java. Addison-Wesley Professional, 2008.
目录
相关文章
|
5月前
|
存储 Python
set()
【10月更文挑战第10天】
42 1
|
10月前
|
存储 C++ 容器
【C++】Map和Set -- 详解(下)
【C++】Map和Set -- 详解(下)
|
10月前
|
JSON 数据格式 Python
set
set
53 4
|
10月前
|
存储 自然语言处理 C++
【C++】Map和Set -- 详解(上)
【C++】Map和Set -- 详解(上)
|
存储 算法 Java
Set详解
Set详解
157 0
|
测试技术
AcDbHatch::setPatternAngle
AcDbHatch::setPatternAngle
new Set与...new Set()的区别
new Set与...new Set()的区别,妙用多多
277 0
GET SET
方法定义
102 0
GET SET
C#——set和get
在面向对象编程(OOP)中,要求把是不允许外界直接对类的成员变量直接访问的,既然不能访问,那定义这些成员变量还有什么意义呢?所以C#中就要用set和get方法来访问私有成员变量,它们相当于外界访问对象的一个通道,一个“接口”。先来看一段代码:
C#——set和get