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.