最近在学习Collection时发现Set集合的一个显著特点: 不包含重复元素. 经过测试之后发现Set集合在向其添加元素时add()和addAll()方法就对元素进行了"审查", 对比查看是否为尚未存在的元素然后选择是否添加进去. 关于这两种方法底层是如何实现的, 就是我在这里想要说明的.
我们知道Set集合是建立在Map的基础之上, 其绝大多数方法构造时都是直接引用了Map中的方法.
这里我们先以HashSet列举一个事例:
HashSet<String> hs = new HashSet<String>();
System.out.println(hs.add(null));
System.out.println(hs.add(null));
System.out.println(hs.add("Shawyeok"));
System.out.println(hs.add("Java"));
System.out.println(hs.add("Shawyeok"));
这里hs在调用add()向内添加元素的时候, 首先会判断元素是否为null(Set的这种不重复元素特性注定会出现一个现象----一个Set集合中最多只能包含一个null元素)若为null则会查找集合中是否有null元素, 若没有则添加成功, 返回true; 反之则添加失败, 返回false.
若元素非null, 则首先调用元素的hashCode()方法得到其哈希值与集合中的各个元素的哈希值一一比较, 如果不相同说明这是两个不同的元素, 可以添加; 如果相同则再调用equals方法对两个元素进行比较, 若equals方法返回true则说明两个元素是同一元素, 不能添加; 反之, 说明两元素非同一元素, 可以添加.
下面是运行结果:
true
false
true
true
false
如何向Set集合中添加我们自己定义的类的对象呢?
上面已经说明了Set集合是如何保证不添加重复元素的, 我们可以想到重写继承自Object类中hashCode()以及equals()方法来保证不添加重复元素. 同样的, 写一个事例:
import java.util.*;
class Test {
public static void main(String[] args) {
HashSet<Person> hs = new HashSet<Person>();
Person Tim = new Person("Tim", Person.MAN, 176);
Person Jine = new Person("Jine", Person.WOMAN, 173);
System.out.println(hs.add(Tim));
System.out.println(hs.add(Jine));
System.out.println(hs.add(new Person("Tim", Person.MAN, 176)));
}
}
class Person {
private String name;
private boolean gender; //true:man ; false:woman
private int height;
public static final boolean MAN = true;
public static final boolean WOMAN = false;
public Person(String name, boolean gender, int height) {
this.name = name;
this.gender = gender;
this.height = height;
}
public int hashCode() {
int sum = name.hashCode() + height*2; //这里height乘以2是为了尽量保证不同元素哈希值的唯一性
if(gender) {
sum++;
} else {
sum--;
}
return sum;
}
public boolean equals(Object obj) {
if(!(obj instanceof Person)) {
return false;
}
Person p = (Person)obj;
if(this.name != p.name) {
return false;
}
if(this.gender != p.gender) {
return false;
}
if(this.height != p.height) {
return false;
}
return true;
}
}
下面是程序打印结果:
true
true
false
从结果可以看出以上的分析是正确的.
注: 以上分析可能会有讲述不妥以及语义欠缺的情况, 敬请谅解.关于Set集合更多特性的详细信息请参考阅读Java源代码.