Source code analysis of javashashset in a Java Collection
1. Introduction We know that Set cannot contain the same elements. If we try to add two identical elements to the same Set, the add method returns false. According to the comments in the source code implementation, we can know that LinkedHashSet is a hash table and Link List Implementation of the Set interface with predictable iteration sequence. This implementation differs from HashSet in that the latter maintains a list of dual links running on all entries. The Link List defines the iteration order, which can be the insertion or access order. Example: package com. test. collections; import java. util. iterator; import java. util. linkedHashSet; public class LinkedHashSetTest {/*** @ param args */public static void main (String [] args) {// TODO Auto-generated method stub incluhashset <Integer> set = new incluhashset <Integer> (); set. add (2); set. add (4); set. add (1); Iterator <Integer> iter = set. iterator (); System. out. println (set. isEmpty (); Syst Em. out. println (set. size (); System. out. println (set. contains (2); System. out. println (set. containsAll (c); System. out. println (set. remove (2); set. clear () ;}} 2. the inheritance structure can be seen from the source code that LinkedHashSet inherits the HashSet class and implements the Set, Cloneable, and Serializable interfaces. By implementing the Set interface, we know that the same elements cannot be contained. But how is this function restricted? Let's take a look at the source code. 3. source code parsing a: Except for a serialized ID, The javashashset class has no other attributes. There are no other methods except several constructors. Other methods are directly inherited from HashSet, let's start with the constructor for simple analysis. Public incluhashset (int initialCapacity, float loadFactor) {super (initialCapacity, loadFactor, true);} public incluhashset (int initialCapacity) {super (initialCapacity ,. 75f, true);} public writable hashset () {super (16 ,. 75f, true);} public writable hashset (Collection <? Extends E> c) {super (Math. max (2 * c. size (), 11 ),. 75f, true); addAll (c);} the four constructors in the Code show different functions. Let's take a look at a simple constructor. The first constructor has two parameters, the second is a parameter, and the third is that no parameter is set to an empty constructor, the fourth constructor initializes the set. If we want to know what the constructor has done, we need to figure out what the super () method has done and what addAll has done. Source code: HashSet (int initialCapacity, float loadFactor, boolean dummy) {map = new LinkedHashMap <E, Object> (initialCapacity, loadFactor);} public boolean addAll (Collection <? Extends E> c) {boolean modified = false; Iterator <? Extends E> e = c. iterator (); while (e. hasNext () {if (add (e. next () modified = true;} return modified;} these two methods are generated by the constructor. In the first HashSet method, there is a Map. What is this. In the original HashSet, there was a HashMap familiar with private transient <E, Object> map. Now we understand that the underlying layer of the original Set is implemented by a Map. This very important thing is to use Map-related method call to simulate the Set function. The Super method creates a Map with the specified size and loading factor. The addAll () method traverses the set and puts them into our Map in sequence, thus, a Set containing values is constructed directly using a Set. Let's look at the above four constructor methods. The first method is to Set the initial capacity and loading factor, and the second constructor is to Set the initial capacity, using the default loading Factor 0.75 of the system. The third constructor directly calls an empty constructor. By default, a Set with a capacity of 16 and a loading Factor of 0.75 is initialized. The last one is to use a Set to initialize the Set. b: iterator () public Iterator <E> iterator () {return map. keySet (). iterator ();} iterator (), call it to return the Set iteration object. The underlying layer is implemented using the Map keySet () method. C: size () public int size () {return map. size ();} directly returns the Map capacity to obtain the number of Set elements. D: isEmpty () public boolean isEmpty () {return map. isEmpty ();} is also used to call the map set to determine whether it is a null method. E: contains () public boolean contains (Object o) {return map. containsKey (o);} checks whether an element exists. F: add () public boolean add (E e) {return map. put (e, PRESENT) = null;} g: remove () and clear () public boolean remove (Object o) {return map. remove (o) = PRESENT;} public void clear () {map. clear ();} When deleting an element, the map method is called. The same is true for clear. 4. The other hashset sets determine the storage location of elements based on the hashCode value of the elements, but they also use the linked list to maintain the order of elements. This makes the elements look like they are saved in the insert order. That is to say, when traversing the set, the sorted hashset will access the elements of the Set in the order they are added. During iterative access to all the elements in the Set, LinkedHashSet performs better than HashSet, but the insert performance is slightly inferior to HashSet. Many operations of Set are implemented by Map. Next time, we will learn about Source Code related to Map.