HashSet for Source Code Analysis

Keywords: Java

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.

Posted by FrancoPaddy on Sun, 07 Jul 2019 15:01:59 -0700