最近在学习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源代码.