concept
HashSet is an implementation of Set interface in Java Collections Framework. The bottom of HashSet is based on HashMap. Having analyzed the source code of HashMap before, it's relatively easy to look at the source code of HashSet.
Class structure

HashSet inherits the AbstractSet class and implements the Set interface. Since HashSet is implemented using HashMap, HashMap is also disorderly in data storage.
Class Membership
PRESENT
private static final Object PRESENT = new Object();
HashMap is a key-to-value K-V model, and HashSet is a common set type. Here PRESENT is used to fill the value in HashMap.
Constructor
HashSet provides four constructors.
// Default parametric constructor public HashSet() { map = new HashMap<>(); } // Construct with existing sets public HashSet(Collection<? extends E> c) { map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16)); addAll(c); } // Constructing initial capacity with parameters: initial size loadFactor: loading factor public HashSet(int initialCapacity, float loadFactor) { map = new HashMap<>(initialCapacity, loadFactor); } // Constructing initial capacity with parameters: initial size public HashSet(int initialCapacity) { map = new HashMap<>(initialCapacity); } // Used only to construct LinkedHashSet usage HashSet(int initialCapacity, float loadFactor, boolean dummy) { map = new LinkedHashMap<>(initialCapacity, loadFactor); }
add method
public boolean add(E e) { return map.put(e, PRESENT)==null; }
The add method is very simple. It calls directly the put method implementation of HashMap. value is filled with PRESENT.
remove method
public boolean remove(Object o) { return map.remove(o)==PRESENT; }
The same is true of the remove method, which calls the remove method of HashMap.
...
Most methods of HashSet are implemented through HashMap.
hashCode Method & Equals Method
If we use HashSet to store custom objects, remember to override the hashCode method and equals method. We will illustrate the necessity of rewriting with an example.
public class Test { String a; public Test(String a) { this.a = a; } public static void main(String[] args) { Set set = new HashSet(); Test o1 = new Test("abc"); Test o2 = new Test("abc"); set.add(o1); set.add(o2); System.out.println(o1.equals(o2)); System.out.println(set.size()); }
The output of the above program should be:
false 2
The default equals method is to determine whether two objects are identical by comparing references. o1 and o2 are obviously two objects, they are not equal, their respective hashcode s are obviously different, so HashSet will treat them as two different objects.
If we want the same object as a to be the same object, using the default equals and hashcode methods obviously can not meet our requirements, at this time we need to rewrite equals and hashcode methods.
@Override public int hashCode() { return 123 * 31 + a.hashCode(); } @Override public boolean equals(Object o) { Test test = (Test) o; return test.a.equals(this.a); }
The result of running main here is:
true 1
summary
HashSet stores elements and operates on them as key s of HashMap, so the order of elements is not guaranteed. HashSet does not have duplicate data, and duplicate data is covered.