1.类图

截屏2021-07-06 上午10.43.12.png

  1. public class HashSet<E>
  2. extends AbstractSet<E>
  3. implements Set<E>, Cloneable, java.io.Serializable {}

继承于AbstractSet抽象类,实现了Set、Cloneable、Serializable接口。

2.成员变量

  1. // 底层是一个hashmap<E, Object>的集合
  2. private transient HashMap<E,Object> map;
  3. // Dummy value to associate with an Object in the backing Map
  4. // 因为 HashMap 是存放键值对的,而 HashSet 只会存放其中的key,即当做 HashMap 的key,
  5. // 而value 就是这个 Object 对象了,HashMap 中所有元素的 value 都是它
  6. private static final Object PRESENT = new Object();

为什么使用PRESENT而不使用null,参见4中的add方法

3. 构造方法

  1. public HashSet() {
  2. map = new HashMap<>();
  3. }
  4. public HashSet(Collection<? extends E> c) {
  5. map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
  6. addAll(c);
  7. }
  8. public HashSet(int initialCapacity, float loadFactor) {
  9. map = new HashMap<>(initialCapacity, loadFactor);
  10. }
  11. public HashSet(int initialCapacity) {
  12. map = new HashMap<>(initialCapacity);
  13. }
  14. // 非public的,意味着它只能被同一个包或者子类调用,这是LinkedHashSet专属的方法。
  15. HashSet(int initialCapacity, float loadFactor, boolean dummy) {
  16. map = new LinkedHashMap<>(initialCapacity, loadFactor);
  17. }

hashSet的构造方法是为了辅助构建map集合。传入的参数都跟map有关:初始容量和加载因子

4.方法

放入的元素一定要重写hashCode和equals方法。
截屏2021-07-06 上午11.12.13.png
HashSet底层的方法都是通过map进行的,所以底层的方法都是调用hashMap的方法。而这些方法全部继承于付了AbstractCollection

  1. // 增
  2. // map的put方法底层在新增节点时如果已经存在该键值,将返回null,(键为e,值统一为同一个Object即PRESENT)
  3. // 所以如果是null,该方法返回false,即不能有重复值
  4. // 在这里使用PRESENT而不使用null,是因为如果值为null,put的时候如果发现相同的key,则会返回旧值
  5. // 而此时旧值就是null,会返回true,即插入了重复值,矛盾。
  6. public boolean add(E e) {
  7. return map.put(e, PRESENT)==null;
  8. }
  9. // 删
  10. // map的remove方法如果删除成功返回该键对应的值(即PRESENT),如果删除成功,该方法返回true,
  11. // 如果不存在,remove方法返回null,该方法返回false。
  12. public boolean remove(Object o) {
  13. return map.remove(o)==PRESENT;
  14. }
  15. // 查
  16. public boolean contains(Object o) {
  17. // 返回的是键的查询
  18. return map.containsKey(o);
  19. }
  20. public int size() {
  21. return map.size();
  22. }
  23. public boolean isEmpty() {
  24. return map.isEmpty();
  25. }
  26. public void clear() {
  27. map.clear();
  28. }
  29. // 迭代器是map的键迭代器
  30. public Iterator<E> iterator() {
  31. return map.keySet().iterator();
  32. }

5. LinkedHashSet

  1. public class LinkedHashSet<E>
  2. extends HashSet<E>
  3. implements Set<E>, Cloneable, java.io.Serializable { }

底层使用LInkedHashMap存储数据,使数据由于链表指针的存在具有有序性,所有的方法均来自父类HashSet,直接调用父类方法即可。

  1. public LinkedHashSet() {
  2. super(16, .75f, true);
  3. }
  4. public LinkedHashSet(int initialCapacity) {
  5. super(initialCapacity, .75f, true);
  6. }
  7. public LinkedHashSet(int initialCapacity, float loadFactor) {
  8. super(initialCapacity, loadFactor, true);
  9. }
  10. public LinkedHashSet(Collection<? extends E> c) {
  11. super(Math.max(2*c.size(), 11), .75f, true);
  12. addAll(c);
  13. }