实现原理
- HashSet 的实现是依赖于 HashMap 的,HashSet 的值都是存储在 HashMap 中的。在 HashSet 的构造法中会初始化一个 HashMap 对象,HashSet 不允许值重复。因此,HashSet 的值是作为 HashMap 的 key 存储在 HashMap 中的,当存储的值已经存在时返回 false
 
- HashSet 非线程安全,允许 null 值,添加值的时候会先获取对象的 hashCode 方法,如果 hashCode 方法返回的值一致,则再调用 equals 方法判断是否一致,如果不一致才 add 元素。HashSet 不保证迭代时顺序,也不保证存储的元素的顺序保持不变
 
接口和属性
1 2 3 4 5 6 7 8 9 10
   | public class HashSet<E> extends AbstractSet<E>      implements Set<E>, Cloneable, java.io.Serializable  {          private transient HashMap<E,Object> map;                private static final Object PRESENT = new Object(); 
      }
   | 
 
构造方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
   | 
 
     public HashSet() {       map = new HashMap<E,Object>();   }  
 
 
 
     public HashSet(Collection<? extends E> c) {       map = new HashMap<E,Object>(Math.max((int) (c.size()/.75f) + 1, 16));       addAll(c);   } 
 
 
 
     public HashSet(int initialCapacity, float loadFactor) {       map = new HashMap<E,Object>(initialCapacity, loadFactor);   }  
 
 
 
     public HashSet(int initialCapacity) {       map = new HashMap<E,Object>(initialCapacity);   }  
 
 
 
 
     public HashSet(int initialCapacity, float loadFactor, boolean dummy) {       map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor);   }  
 
  | 
 
插入
1 2 3 4 5 6 7 8 9 10 11 12 13
   | 
 
 
 
 
 
 
 
     public boolean add(E e) {       return map.put(e, PRESENT)==null;   } 
 
  | 
 
删除
1 2 3 4 5 6 7 8 9
   | 
 
 
 
     public boolean remove(Object o) {       return map.remove(o)==PRESENT;   }  
 
  | 
 
包含
1 2 3
   | public boolean contains(Object o) {     return map.containsKey(o); }
  | 
 
其他
怎么保证元素不重复?
元素值作为的是 map 的 key,map 的 value 则是 PRESENT 变量,这个变量只作为放入 map 时的一个占位符而存在,没实际用处。HashMap 的 key 是不能重复的,而 HashSet 的元素又作为 map 的 key,所以也不能重复
为什么 val 要放上一个静态常量 present?
- HashMap 使用 put 的时候,会把 put 的数据放在其位置上,如果该位置上已经存在当前 key,会对其 key 映射的 val 给替换掉,并且返回之前的 val;如果没有 key,则返回 null
 
- val 放了一个 hashset 类的静态常量 present,如果 put 返回的是 null,不是 present,就说明 put 的 key 是不存在的,add 也会返回 true。如果 put 返回的是 present 就说明之前的 key 是存在的,并不是没有 put 上,所以 add 方法返回的 false 并不是存失败的意思
 
HashSet 是有序的吗?
HashSet 是无序的,它不能保证存储和取出顺序一致
1 2 3 4 5 6 7 8 9 10 11 12 13
   | public class SetOfInteger {     public static void main(String[] args) {         Random rand = new Random(47);         Set<Integer> intset = new HashSet<Integer>();         for (int i = 0; i<10000; i++) {             intset.add(rand.nextInt(30));         }         System.out.println(intset);     } }
 
 
 
  | 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
   |  public boolean add(E e) {     return map.put(e, PRESENT)==null; }
 
  public V put(K key, V value) {     return putVal(hash(key), key, value, false, true); }
 
  static final int hash(Object key) {     int h;     return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }
 
  public static int hashCode(int value) {     return value; }
 
  | 
 
Integer 中 hashCode 方法的返回值就是这个数本身,当数值小于 65536 时,得到的 hash 值是本身,插入到 HashMap 中的顺序即 hash 的顺序,所以是有序的;当超过该值时,HashSet 是无序的