java -- HashSet

java -- HashSet

 

   A HashSet is a collection with no repeating elements.

 

 

advantage

 

  • no repeating elements
  • element can be null
  • The operation is very simple, more like a "package" of HashMap, and only the key of HashMap is used to implement various features.

 

 

shortcoming

 

  • The order of the elements is not guaranteed
  • Asynchronous, that is, there will be fail-fast

 

 

 

working principle

 

    According to the source code, the bottom layer of HashSet is HashMap, which uses Key, and Value will create a new object internally.

 

    The source code is as follows:

package java.util;

public class HashSet<E>
    extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable
{
    static final long serialVersionUID = -5024744406713321676L;

    // HashSet saves content through map (HashMap object)
    private transient HashMap<E,Object> map;

    // PRESENT is to insert the value corresponding to the key-value into the map
    // Because only the key is used in HashSet, and HashMap is a key-value key-value pair;
    // Therefore, when adding a key-value pair to the map, the value of the key-value pair is fixed to PRESENT
    private static final Object PRESENT = new Object();

    // default constructor
    public HashSet() {
        // Call the default constructor of HashMap to create a map
        map = new HashMap<E,Object>();
    }

    // constructor with collection
    public HashSet(Collection<? extends E> c) {
        // Create a map.
        // Why call Math.max((int) (c.size()/.75f) + 1, 16), choose a larger tree from (c.size()/.75f) + 1 and 16 Woolen cloth?        
        // First, specify (c.size()/.75f) + 1
        // Because considering the efficiency (time cost and space cost) of HashMap, the load factor of HashMap is 0.75.
        // When the "threshold" of HashMap (threshold = total size of HashMap * loading factor) < "actual size of HashMap",
        // You need to double the capacity of HashMap.
        // So, (c.size()/.75f) + 1 calculates exactly the total space size.
        // Next, explain why it is 16.
        // The total size of the HashMap must be an exponential multiple of 2. If the specified size is not an exponential multiple of 2 when creating a HashMap;
        // The constructor of HashMap will also recalculate to find the smallest exponential multiple of 2 that is larger than the "specified size".
        // Therefore, 16 is specified here for performance reasons. Avoid double counting.
        map = new HashMap<E,Object>(Math.max((int) (c.size()/.75f) + 1, 16));
        // Add all elements in set (c) to HashSet
        addAll(c);
    }

    // Constructor that specifies the initial capacity and load factor of the HashSet
    public HashSet(int initialCapacity, float loadFactor) {
        map = new HashMap<E,Object>(initialCapacity, loadFactor);
    }

    // Constructor that specifies the initial capacity of HashSet
    public HashSet(int initialCapacity) {
        map = new HashMap<E,Object>(initialCapacity);
    }

    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
        map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor);
    }

    // return iterator of HashSet
    public Iterator<E> iterator() {
        // Actually what is returned is the "key collection iterator" of HashMap
        return map.keySet().iterator();
    }

    public int size() {
        return map.size();
    }

    public boolean isEmpty() {
        return map.isEmpty();
    }

    public boolean contains(Object o) {
        return map.containsKey(o);
    }

    // Add element (e) to HashSet
    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }

    // delete the element in the HashSet (o)
    public boolean remove(Object o) {
        return map.remove(o)==PRESENT;
    }

    public void clear() {
        map.clear();
    }

    // Clone a HashSet and return an Object object
    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();
        }
    }

    // java.io.Serializable write function
    // Write the "total capacity, load factor, actual capacity, and all elements" of the HashSet to the output stream
    private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException {
        // Write out any hidden serialization magic
        s.defaultWriteObject();

        // Write out HashMap capacity and load factor
        s.writeInt(map.capacity());
        s.writeFloat(map.loadFactor());

        // Write out size
        s.writeInt(map.size());

        // Write out all elements in the proper order.
        for (Iterator i=map.keySet().iterator(); i.hasNext(); )
            s.writeObject(i.next());
    }


    // The read function of java.io.Serializable
    // Read out the "total capacity, load factor, actual capacity, all elements" of HashSet in turn
    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        // Read in any hidden serialization magic
        s.defaultReadObject();

        // Read in HashMap capacity and load factor and create backing HashMap
        int capacity = s.readInt();
        float loadFactor = s.readFloat();
        map = (((HashSet)this) instanceof LinkedHashSet ?
               new LinkedHashMap<E,Object>(capacity, loadFactor) :
               new HashMap<E,Object>(capacity, loadFactor));

        // Read in size
        int size = s.readInt();

        // Read in all elements in the proper order.
        for (int i=0; i<size; i++) {
            E e = (E) s.readObject();
            map.put(e, PRESENT);
        }
    }
}

 

 

 

Construction method

 

// default constructor
public HashSet()

// constructor with collection
public HashSet(Collection<? extends E> c)

// Constructor that specifies the initial capacity and load factor of the HashSet
public HashSet(int initialCapacity, float loadFactor)

// Constructor that specifies the initial capacity of HashSet
public HashSet(int initialCapacity)

// The constructor that specifies the initial capacity and load factor of HashSet, dummy has no effect
HashSet(int initialCapacity, float loadFactor, boolean dummy)

 

 

 

Main API

 

boolean         add(E object)
void            clear()
Object          clone()
boolean         contains(Object object)
boolean         isEmpty()
Iterator<E>     iterator()
boolean         remove(Object object)
int             size()

 

 

 

 

Traversal

 

Traverse HashSet through Iterator

 

  • Get the iterator of HashSet according to iterator().
  • Traverse the iterator to get each element.
// Assume set is a HashSet object
for(Iterator iterator = set.iterator();
       iterator.hasNext(); ) {
    iterator.next();
}

 

 

Traverse HashSet with for-each

 

  • Obtain the array corresponding to the element collection of HashSet according to toArray().
  • Traverse the array to get each element.
// Suppose the set is a HashSet object, and the elements in the set are of type String
String[] arr = (String[])set.toArray(new String[0]);
for (String str:arr)
    System.out.printf("for each : %s\n", str);

 

 

 

 

Insert, modify, store data

 

    Whether it is query, access, modification speed is very fast.

 

 

 

 

Adjust capacity

 

  • The default initial capacity is 16
  • The load factor is 0.75: that is, when the number of elements exceeds 0.75 times the capacity length, the capacity is expanded
  • Capacity expansion increment: 1 times the original capacity
  • For example, the capacity of HashSet is 16, and the capacity is 32 after one expansion

 

 

 

Concurrent processing

 

    Because it is not thread-safe, fail-fast will still occur in the case of multi-threading.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=327042403&siteId=291194637