Set的概念与其在数学上的意义相同,是一种不允许存在重复元素的特殊集合,即:在一个Set中不包含满足条件e1.equals(e2)
的元素对e1
和e2
。Set接口在从Collection中继承的接口的基础上,增加了额外的限制条件,主要包括的方法为:构造方法,add方法,equal方法和hashcode方法。为了描述的方便,在Set接口中声明的方法包含了由Collection中继承的接口。
构造方法的限制条件为:所有的构造方法必须构造一个不包含重复元素的集合。
注意:需要特别注意包含易变对象的集合。因为,Set接口中,没有定义当其中的一个元素在改变过程与集合中另一个元素相等时的处理策略。因此出于这种考虑,集合是不能将自身作为一个元素添加到自身中的。对于这种情况,编写如下测试类:
import java.util.HashSet;
import java.util.Set;
public class EqualClass {
private int id;
public EqualClass(int id) {
this.id = id;
}
@Override
public int hashCode() {
return 1;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public boolean equals(Object obj) {
if (obj == null || !(obj instanceof EqualClass)) {
return false;
}
EqualClass o = (EqualClass) obj;
return this.id == o.id;
}
@Override
public String toString() {
return "id " + this.id;
}
public static final void main(String[] args) {
Set set = new HashSet();
EqualClass class1 = new EqualClass(1);
EqualClass class2 = new EqualClass(2);
EqualClass class3 = new EqualClass(1);
set.add(class1);
set.add(class2);
set.add(class3);
System.out.println(class1.equals(class2));
System.out.println(set);
class2.setId(1);
System.out.println(class1.equals(class2));
System.out.println(set);
}
}
输出结果如下:
false
[id 2, id 1]
true
[id 1, id 1]
由此可以看出,在开始时,由于class3与class1相等,因此,在添加到集合中时,并不会出现重复元素。而在class2在添加入集合后,发生修改,与class1相等,但是集合中并没有排除重复元素,因此可能导致集合以后不可预期的行为,在编码中应当特殊注意这种类似的情况发生。
一些Set接口的实现对于其中包含的元素有严格的限制。例如:有些实现不允许null元素,有些对元素的类型有限制。当试图向集合中添加一个不满足条件的元素时,则会抛出一个非检查(unchecked)异常,一般为:NullPointerException
或者ClassCastException
。当试图检索一个非法元素时,由两种处理方式:抛出异常,返回false。
在本文中,将针对一些与Collection中不同的接口进行介绍,其通用接口的介绍参见:java.util.Collection学习笔记。
Iterator iterator();
返回一个基于Set中元素的迭代器。与列表中的迭代器不同,Set迭代器放回元素的顺序是不定的(除非集合的实现中提供了对于结合元素返回顺序的支持)。
boolean add(E e);
将元素e添加到集合中。如果集合中已经包含与此元素相等的元素,则该操作不会对集合产生任何的修改,并返回false。与Set实现类提供的构造方法相结合,可以在一定程度上保证集合中不包含重复的元素。但是以上的这些额外限制并不意味着集合会接收所有的元素。Set可能拒绝一些特殊元素(如null),并抛出一个异常。当自己在实现Set接口时,需要明确说明其中可以包含的元素的限制条件。
boolean addAll(Collection extends E> c);
将集合c中所有元素添加到指定Set中。在添加过程中,需要进行排重操作。如果c也是一个Set,那么addAll操作即是数学中的并集操作。但是在执行本方法的过程中,如果c中的元素发生改变,将产生不可预期的操作结果。
boolean retainAll(Collection> c);
在Set中仅保留c中包含的元素,将Set中的其它元素删除。如果c也是一个Set,则本方法的操作结果相当于二者取交集。
boolean removeAll(Collection> c);
从Set中删除集合c中的所有元素。如果c也是一个Set,则本方法的操作结果相当于数学中的差集操作。
boolean equals(Object o);
判断Set与对象o是否相等。当o也是一个Set,并且与Set包含相同的元素时,返回true,否则返回false;这个方法保证了不同Set接口实现类之间进行等价比较时的正确性。
int hashCode();
计算当前Set的hash code。一个Set的哈希值是当前集合中包含的所有元素的哈希值的和(其中null元素的哈希值被定义为0)。这保证了对于任意两个集合s1和s2,当s1.equals(s2)
时有s1.hashCode()==s2.hashCode()
。