Set集合的基本特征是不记录添加顺序,不允许元素重复(想想是为什么)。最常用的实现类是HashSet.
本文将要介绍以下内容
- HashSet类
- HashSe的特征
- HashSet的equals和hashCode
- LinkedHashSet的特征
- TreeSet的特征
- EnumSet的特征
HashSet类
HashSet类直接实现了Set接口, 其底层其实是包装了一个HashMap去实现的。HashSet采用HashCode算法来存取集合中的元素,因此具有比较好的读取和查找性能。
HashSet的特征
- 不仅不能保证元素插入的顺序,而且在元素在以后的顺序中也可能变化(这是由HashSet按HashCode存储对象(元素)决定的,对象变化则可能导致HashCode变化)
- HashSet是线程非安全的
- HashSet元素值可以为NULL
HashSet的equals和HashCode
前面说过,Set集合是不允许重复元素的,否则将会引发各种奇怪的问题。那么HashSet如何判断元素重复呢?
HashSet需要同时通过equals和HashCode来判断两个元素是否相等,具体规则是,如果两个元素通过equals为true,并且两个元素的hashCode相等,则这两个元素相等(即重复)。
所以如果要重写保存在HashSet中的对象的equals方法,也要重写hashCode方法,重写前后hashCode返回的结果相等(即保证保存在同一个位置)。所有参与计算 hashCode() 返回值的关键属性,都应该用于作为 equals() 比较的标准。
试想如果重写了equals方法但不重写hashCode方法,即相同equals结果的两个对象将会被HashSet当作两个元素保存起来,这与我们设计HashSet的初衷不符(元素不重复)。
另外如果两个元素哈市Code相等但equals结果不为true,HashSet会将这两个元素保存在同一个位置,并将超过一个的元素以链表方式保存,这将影响HashSet的效率。
如果重写了equals方法但没有重写hashCode方法,则HashSet可能无法正常工作,比如下面的例子。
package colection.HashSet;
import java.util.HashSet;
import java.util.Iterator;
public class R {
public int count;
public R(int count) {
this.count = count;
}
public String toString() {
return "R[count:" + count +" # hashCode:"+this.hashCode()+"]";
}
public boolean equals(Object obj) {
if(this == obj) return true;