Java Containers HashSet and LinkedHashSet Source Code Parsing

Posted by Liodel on Wed, 26 Jun 2019 19:24:32 +0200

Written in front

This article focuses on the source code analysis of Java 1.6, which may differ from other versions.

Summary

HashSet and LinkedHashSet are implemented with HashMap and LinkedHashMap respectively. They store data as Key values in HashMap or LinkedHashMap. Therefore, Sets are not allowed to have duplicate values, and HashSets are disordered and LinkedHashSets are ordered. Previously, HashMap and LinkedHashMap have been introduced. You can refer to them separately. Java container HashMap source code parsing and Java container LinkedHashMap source code parsing .

Source code parsing

LinkedHashSet is inherited from HashSet, so let's first look at the source code of HashSet.

Attributes and Construction Method

    //Used to store data
    private transient HashMap<E,Object> map;

    //Values stored in HashMap
    private static final Object PRESENT = new Object();

    //By default, create a new HashMap with 16 capacity and 0.75 load factor
    public HashSet() {
        map = new HashMap<E,Object>();
    }

    //Construction Method with collection Parameter
    public HashSet(Collection<? extends E> c) {
        map = new HashMap<E,Object>(Math.max((int) (c.size()/.75f) + 1, 16));
        addAll(c);
    }

    //Constructing Method of Given Capacity and Loading Factor
    public HashSet(int initialCapacity, float loadFactor) {
        map = new HashMap<E,Object>(initialCapacity, loadFactor);
    }

    //Constructing method of given capacity
    public HashSet(int initialCapacity) {
        map = new HashMap<E,Object>(initialCapacity);
    }

    //With the dummy parameter added, this construction method will be used in LinkedHashSet
    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
        map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor);
    }

The constructor with the collection parameter uses the addAll method, which is not overridden in HashSet, so the method in AbstractCollection is directly used here. The code is as follows:

    public boolean addAll(Collection<? extends E> c) {
        boolean modified = false;
        Iterator<? extends E> e = c.iterator();
        //Traversal collection iterator
        while (e.hasNext()) {
            //Call the add method of the corresponding container
            if (add(e.next()))
            modified = true;
        }
        return modified;
    }

Two attributes are defined in HashSet. Map is used to store data. PRESENT is the default value when data is stored in map. It has five constructors, the first four of which call the corresponding constructor of HashMap to initialize the map. The last dummy function is provided for LinkedHashSet. LinkedHashSet initializes the map by calling the construction method of LinkedHashMap.

Other methods

    //Iterator, because HashSet is equivalent to traversing the key of HashMap, returns directly
    //The iterator of keySet in map is enough. So HashSet is also out of order.
    public Iterator<E> iterator() {
        return map.keySet().iterator();
    }

    //Return size, return map size directly
    public int size() {
        return map.size();
    }

    //To judge whether a map is empty is to judge whether a map is empty.
    public boolean isEmpty() {
        return map.isEmpty();
    }

    //To determine whether a value is included, call the containsKey method of map directly
    public boolean contains(Object o) {
        return map.containsKey(o);
    }

    //Add elements and call the put method of map directly
    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }

    //Delete the element and call the remove method of map directly
    public boolean remove(Object o) {
    return map.remove(o)==PRESENT;
    }

    //Empty Set, directly calling the empty method of map
    public void clear() {
        map.clear();
    }

    //Copy set
    public Object clone() {
        try {
            HashSet<E> newSet = (HashSet<E>) super.clone();
            newSet.map = (HashMap<E, Object>) map.clone();
            return newSet;
        } catch (CloneNotSupportedException e) {
            throw new InternalError();
        }
    }

These methods provided by HashSet are implemented by calling the corresponding methods of HashMap, which are not detailed here. If you are not familiar with the specific implementation of these methods in HashMap, please refer to the two blog posts mentioned at the beginning of this article.

LinkedHashSet Construction Method

After introducing HashSet, let's take a look at the implementation of LinkedHashSet. LinkedHashSet is inherited from HashSet. It provides only four constructors by calling the last constructor of HashSet. The code is as follows:

    //Construction Method of Given map Capacity and Loading Factor
    public LinkedHashSet(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor, true);
    }

    //For a given capacity, the load factor defaults to 0.75.
    public LinkedHashSet(int initialCapacity) {
        super(initialCapacity, .75f, true);
    }

    //Default construction method, capacity with default value 16, load factor with default value 0.75
    public LinkedHashSet() {
        super(16, .75f, true);
    }

    //Construction Method with collection Parameter
    public LinkedHashSet(Collection<? extends E> c) {
        super(Math.max(2*c.size(), 11), .75f, true);
        addAll(c);
    }

Topics: Java