1. Introduction
We know that Set cannot contain the same element. 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:
| The code is as follows: |
Copy code |
Package com. test. collections;
Import java. util. Iterator;
Import java. util. LinkedHashSet;
Public class extends hashsettest {
/**
* @ Param args
*/
Public static void main (String [] args ){
// TODO Auto-generated method stub
LinkedHashSet <Integer> set = new LinkedHashSet <Integer> ();
Set. add (2 );
Set. add (4 );
Set. add (1 );
Iterator <Integer> iter = set. iterator ();
System. out. println (set. isEmpty ());
System. 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. Inheritance structure
From the source code, we can see that javashashset 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 LinkedHashSet class has no other attributes. There are no other methods except several constructors. Other methods are directly inherited from the HashSet class, let's start with the constructor for simple analysis.
| The code is as follows: |
Copy code |
Public writable hashset (int initialCapacity, float loadFactor ){
Super (initialCapacity, loadFactor, true );
}
Public writable hashset (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 );
} |
We can see that the four constructors in the code have 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. View source code:
| The code is as follows: |
Copy 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;
} |
In the past, these two methods appeared in 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 ()
| The code is as follows: |
Copy code |
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 ()
| The code is as follows: |
Copy code |
Public int size (){
Return map. size ();
} |
The number of Set elements is obtained by directly returning the Map capacity.
D: isEmpty ()
| The code is as follows: |
Copy code |
Public boolean isEmpty (){
Return map. isEmpty ();
} |
It is also used to call whether the map set is empty.
E: contains ()
| The code is as follows: |
Copy code |
Public boolean contains (Object o ){
Return map. containsKey (o );
} |
Determines whether an element is contained.
F: add ()
| The code is as follows: |
Copy code |
Public boolean add (E e ){
Return map. put (e, PRESENT) = null;
} |
G: remove () and clear ()
| The code is as follows: |
Copy code |
Public boolean remove (Object o ){
Return map. remove (o) = PRESENT;
}
Public void clear (){
Map. clear ();
} |
When deleting an element, map is called, and clear is the same.
4. Others (summary)
The LinkedHashSet set determines the storage location of elements based on the hashCode value of the elements, but it also uses 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.