In the world of Java programming, the JDK source code is like a mysterious treasure, in which the Set class is a powerful tool that we frequently use in our daily development. Today, like a brave explorer, let's go deep into the JDK source code to unveil the mystery of the Set class, with a focus on analyzing the clever application of the adapter pattern, and see how it makes the Set class glow with its unique charm! 💥
I. The Set class: an important role in the common data structure 🎯
In our programming journey, the Set class is like an organized toolbox, it has the property of not allowing duplicate elements to be stored, which makes it play a crucial role in dealing with data de-duplication, set operations and other scenarios. Whether it is processing user input data, managing system configuration items, or filtering data in complex algorithms, the Set class can help us a lot. But have you ever wondered how the Set class implements the uniqueness judgment of elements at the bottom 🧐?
II. The Adapter Pattern: The Hidden Power Behind the Set Class 🌟
(i) Secrets in class diagrams
When we look at the class diagram of the Set class in the JDK source code, we will be surprised to find the figure of a classic design pattern - adapter pattern. Like a magical wizard, it cleverly wraps the object of the Map interface into the Set interface, realizing the seamless conversion between the two different interfaces.
(ii) HashSet: An Example of the Adapter Pattern
-
Underlying structure: relies on HashMap
In the HashSet source code, we find that it holds a transient HashMap instance internally:
private transient HashMap<E,Object> map;
// For use with HashMap The dummy value associated with the element in the
private static final Object PRESENT = new Object();
The HashMap is the key "hero" behind the implementation of Set. HashSet cleverly uses the characteristics of the HashMap to implement its own functionality.
2. Add element: delegate to HashMap
When we call the add method of the HashSet, we are actually using the elements as the keys of the HashMap, and the fixed PRESENT object as the value, which is stored in the HashMap:
public boolean add(E e) {
return (e, PRESENT)==null;
}
In this way, the uniqueness of the elements in the Set is easily ensured by the uniqueness of the HashMap key. When we add elements to a HashSet, it's like putting items into a specially modified HashMap container, which is automatically de-weighted for us.
3. Iterator: Get an iterator over the Map's keys.
And when we get the iterator of a HashSet, it directly returns an iterator over the set of keys of the HashMap:
public Iterator<E> iterator() {
return ().iterator();
}
This makes it so that when we traverse the HashSet, we're actually traversing the keys of the HashMap to get all the elements of the Set.
(iii) LinkedHashSet: similar adaptation logic
The LinkedHashSet implementation is also unique. It calls the constructor of the parent class in the constructor, which ultimately creates a LinkedHashMap:
public LinkedHashSet(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor, true);
}
// The other constructors are similar in that they all end up calling the parent constructor to create the LinkedHashMap.
Its constructor will eventually call to a parent class constructor like this one:
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
LinkedHashSet utilizes the ordered nature of LinkedHashMap, which not only achieves element uniqueness, but also maintains the order in which elements are inserted, providing us with an ordered implementation of Set.
(iv)TreeSet:adapter NavigableMap
The TreeSet implementation also relies on the adapter pattern, which holds a transient NavigableMap instance internally:
private transient NavigableMap<E,Object> m;
private static final Object PRESENT = new Object();
TreeSet achieves orderly storage and manipulation of elements by storing them in NavigableMap and using its sorting function, providing us with an ordered and non-repeating Set collection.
III. More than just the adapter pattern: shades of the bridge pattern 🤔
Interestingly, when analyzing the implementation of the Set class in the JDK source code, we can also find some traces of deformation similar to the bridge pattern. Although in essence, the implementation here is more in line with the definition of the adapter pattern, this similarity also allows us to think more deeply about the use of design patterns. It is like a bridge between different design concepts, allowing us to see the subtle connections and flexible transformations that may exist between design patterns in actual programming.
IV. Summary and insights: the value of source code learning 💡
Through in-depth analysis of the JDK source code of the Set class on the application of the adapter pattern, we not only unveil the Set class efficiently achieve the mystery of the uniqueness of the element judgment and operation, but also deeply appreciate the great power of the design pattern in optimizing the code structure and improving the reusability and flexibility of the code. This is like lighting a lamp in the darkness, which points out the direction for our future programming practice.
In our daily programming, we should not just be satisfied with using ready-made classes and interfaces, but we should go deeper into the source code like this to learn the design ideas and techniques of the masters. Only in this way can we continue to improve our programming skills and build more efficient, robust and elegant software systems. I hope that today's exploration can become a valuable asset on your programming journey, so let's continue to swim in the sea of source code together and discover more wisdom crystals! 🚀
Author:Mr. Die's Programming Class
Provenance:/
If you like this article, please long press the QR code, attention!Java Code World Exploration
.