Hashmap research

xiaoxiao2021-03-06  13

Hashtable and havehmap

HashTable inherits from the Dictionary class, and Hashmap is a implementation of the Map Interface introduced by Java1.2. HashMap allows null as a key or value of the entry, and HashTable is not allowed, and HashMap puts the HashTable's contAins method, changed ContainsValue and Containskey. Because the Contains method is easy to cause misunderstandings. The biggest difference is that the HashTable method is Synchronize, and HashMap is not, when accessed HashTable, does not need to be synchronized for its method, and HashMap must provide external synchronization. Hash / rehash algorithms used by HashTable and Hashmap are probably, so performance will not have a big difference.

Hashtable is very wide, Hashmap is a class used in the new framework that replaces the HashTable, that is, it is recommended to use HashMap, do not use HashTable. Maybe you think is Hashtable is very easy to use, why don't you use it? It is simply analyzed their differences here.

1.Hashtable method is synchronized, and HashMap does not synchronize, so you have to manually synchronize the difference in Multi-threaded HashMap is like vector and arraylist.

2.Hashtable does not allow NULL values ​​(Key and Value can not be), HashMap allows NULL values ​​(Key and Value can be).

3.Hashtable has a Contains (Object Value), the function and the ContainSValue feature.

4.Hashtable uses ENUMERATION, Hashmap uses Iterator.

The above is only the surface of the surface, and their implementation is very different.

5. Hashtable Default size is 11, the increased method is OLD * 2 1. The default size of the HASH array in HashMap is 16, and must be 2 index.

6. The use of the hash value, the HashTable directly uses the object's hashcode, the code is like this: int has = key.hashcode (); int index = (hash & 0x7fffffff)% Tab.Length; HashMap recalculate the Hash value. And use with instead of demodulation: int has = hash (k); int I = indexfor (hash, table.Length); static int hash (object x) {int h = x.hashcode ();

H = ~ (h << 9); h ^ = (h >>> 14); h = (h << 4); h ^ = (h >>> 10); Return H;} static int indexFor (INT H, INT Length) {RETURN H & (Length-1);} The above is just some of the more prominent differences, of course, their implementation still has a lot of different, such as HashMap to NULL operations.

1.Hashtable method is synchronized, and HashMap does not synchronize, so you have to manually synchronize the difference in Multi-threaded HashMap is like vector and arraylist.

2.Hashtable does not allow NULL values ​​(Key and Value can not be), HashMap allows NULL values ​​(Key and Value can be).

3.Hashtable has a Contains (Object Value), the function and the ContainSValue feature. 4.Hashtable uses ENUMERATION, Hashmap uses Iterator.

The above is only the surface of the surface, and their implementation is very different.

5. Hashtable Default size is 11, the increased method is OLD * 2 1. The default size of the HASH array in HashMap is 16, and must be 2 index.

6. The use of the hash value, the HashTable directly uses the object's hashcode, the code is like this: int has = key.hashcode (); int index = (hash & 0x7fffffff)% Tab.Length; HashMap recalculate the Hash value. And use with instead of demodulation: int has = hash (k); int I = indexfor (hash, table.Length); static int hash (object x) {int h = x.hashcode ();

H = ~ (h << 9); h ^ = (h >>> 14); h = (h << 4); h ^ = (h >>> 10); Return H;} static int indexFor (INT H, INT Length) {RETURN H & (Length-1);} The above is just some of the more prominent differences, of course, their implementation still has a lot of different, such as HashMap to NULL operations.

Java Collectes --- HashMap Depth Analysis and Comparison

Linear tables, linked lists, haveh tables are commonly used data structures. When Java development, JDK has provided us with a series of corresponding classes to implement basic data structures. These classes are in the java.util package. This paper tries to explain the role of each class and how to use these classes correctly by simply description.

Collection├List│├LINKEDLIST│├ArrayList│ └Vector│ └Stack └SETMAP├SHASHTABLE ├STMAP└Weakhashmap

The Collection Interface Collection is the most basic set interface, a collection represents a set of object, ie the element of Collection (Elements). Some Collection allows the same elements and others. Some can sort and others can not work. Java SDK does not provide a class directly inherited from Collection, and the classes provided by Java SDK are inherited from the "sub-interface" such as List and SET. All classes for implementing the Collection interface must provide two standard constructor: None parameters for creating an empty collection, a constructor with a Collection parameter is used to create a new Collection, this new Collection and biography Into Collection has the same elements. The latter constructor allows the user to copy a collection. How to traverse each element in Collection? Regardless of the actual type of Collection, it supports a method of Iterator (), which returns an iteration, using this iteration to access each element in the Collection one by one. Typical usage is as follows: Iterator it = Collection.iterator (); // Get an iterative while (it.hasnext ()) {Object Obj = it.next (); // Get the next element} derived by the Collection interface The two interfaces are LIST and SET. The List interface list is an ordered Collection that can accurately control the insertion of each element using this interface. Users can use an index (the location of the element in LIST, similar to the array subscript) to access the elements in the list, similar to the number of Java. Unlike the SET to be mentioned below, List allows the same elements. In addition to the Iterator () method with the Collection interface, List also provides a listiterator () method, returning a listiterator interface, compared to the standard Iterator interface, the Listiterator is more than some add () methods, allowed to add, Delete, set the element, but also traverse forward or backward. Realize the common class of List interfaces with LinkedList, ArrayList, Vector and Stack.

LinkedList class LinkedList implements a List interface, allowing NULL elements. In addition, LinkedList provides additional GET, REMOVE, and INSERT method in the head or tail of LinkedList. These operations allow LinkedList to be used as a stack, queue, or a two-way queue (DEQUE). Note that LinkedList has no synchronization method. If multiple threads accesses a list, you must implement access synchronization yourself. One solution is to construct a synchronized list: list list = collections.synchronizedlist (new linkedlist (...));

ArrayList class ArrayList implements an array of variable sizes. It allows all elements, including NULL. ArrayList is not synchronized. Size, ISEMPTY, GET, and SET methods run time are constants. However, the ADD method is overhead as a constant of the distribution, and the time to add N elements that require o (n). Other method run times is linear. Each ArrayList instance has a capacity, that is, the size of the array for storing the element. This capacity can be automatically increased as new elements continue, but the growth algorithm is not defined. When you need to insert a large number of elements, you can call the EnSureCapacity method before insertion, you can increase the capacity of ArrayList to increase the insertion efficiency. Like LinkedList, ArrayList is also unsynchronized. VECTOR class Vector is very similar to ArrayList, but the vector is synchronized. Iterator created by Vector, although Iterator created with ArrayList is the same interface, but because the vector is synchronized, when an Iterator is created and is being used, the other thread changes the status of the Vector (for example, add or delete some Element), when you call the method of Iterator, the ConcURRentModificationException will thus be thrown, so the exception must be captured.

The Stack class stack inherits from the vector to implement a stack of a backward first. STACK provides 5 additional methods such that the vector is used as a stack. Basic PUSH and POP methods, as well as the PEEK method to get the elements of the top of the stack, the EMPTY method tests whether the stack is empty, the Search method detects the position of an element in the stack. Stack is just after being created.

Set Interface Set is a collection that does not contain duplicate elements, that is, any two elements E1 and E2 have E1.Equals (E2) = false, and SET has a NULL element. Obviously, the SET constructor has a constraint, and the incoming Collection parameter cannot contain a repeated element. Note: You must be careful to operate the variable object (Mutable Object). If the variable element in a set changed its own state, it will result in object.equals (object) = true.

Map interface Please note that MAP does not inherit the Collection interface, and the MAP provides key to value mapping. The same key can not contain the same key, each of which can only map a value. The MAP interface provides three sets of views, and the contents of the MAP can be treated as a set of Key collections, a set of value collections, or a set of Key-Value mappings.

HashTable class hashtable inherits the MAP interface to implement a Hach-Value mapping hash. Any non-null object can be used as a key or value. Add data Using PUT (Key, Value), remove the data using GET (KEY), the time overhead of these two basic operations is constant. HashTable Tuninescence through the INITIAL CAPACITY and LOAD FACTOR. Usually the default Load Factor 0.75 excellent time and space balance. Increasing the Load Factor can save space but the corresponding lookup time will increase, which affects operations like get and PUT. With a simple example of using HashTable, put 1, 2, 3 in Hashtable, their Key is "one", "two", "three": Hashtable number = new hashtable (); NumBers.put ("one" , New Integer (1)); NumBers.Put ("Two", New Integer (2)); NumBers.Put ("Three", New Integer (3)); Take a number, such as 2, with the corresponding Key : Integer n = (Integer) Numbers.get ("Two"); System.out.println ("Two =" N); Since the object as a key will determine the Value corresponding to the hash function Location, therefore any object as a Key must implement a HashCode and Equals method. Hashcode and Equals methods inherit from the root object, if you use a custom class as a key, be quite careful, follow the definition of the hash function, if the two objects are the same, ie obj1.equals (obj2) = true, then Their HashCode must be the same, but if the two objects are different, their hashcode is not necessarily different. If the two different objects of HashCode are the same, this phenomenon is called conflict, and the conflict will result in an increase in the time overhead of the operation hash. So try to define the HashCode () method to speed up the operation of the hash table. If the same object has a different HashCode, the operation of the hash table will have unexpected results (the expected GET method returns null), to avoid this problem, just keep in mind: To copy the equals method and havehcode method, Not only to write one of them. Hashtable is synchronized. HashMap class HashMap and HashTable are similar, and the HashMap is non-synchronous and allows NULL, NULL VALUE, and NULL KEY. However, when HashMap is treated as a Collection (VALUES () method can return to Collection, its iterative subsystem is overhead, and the capacity of HashMap is proportional. Therefore, if the performance of iterative operation is quite important, do not set the initial capacity of HashMap, or Load Factor is too low.

WeakhashMap class WeakhashMap is an improved HashMap that implements "weak references" for Key, if a key is no longer referenced outside, then the key can be recycled by GC.

Summary If it is involved in stacks, queues, etc., consider using List, for quick plug, delete elements, should use LinkedList, if you need to quickly random access, you should use ArrayList. If the program is in a single threaded environment, or the access is only in one thread, considering the non-synchronous class, its efficiency is high, if multiple threads may operate a class at the same time, the synchronous class should be used. Pay special attention to the operation of the hash table, as a key to Key, to properly reply Equals and HashCode methods. Try to return to the interface instead of the actual type, if you returns List instead of arraylist, the client code does not have to change when you need to change ArrayList to linkedList. This is for abstract programming. In Java's depth analysis of HashMap and comparing in the world of Java, regardless of the class, the structure of its structure is the key to the logic and performance of the entire program. Since I have contacted a problem with the performance and logic coexisting, I started researching this problem. Looking for a large and small forum, I also find the "Java Virtual Machine Specification", "Apress, .java.collections. (2001), BM.OCR.6.0.SHARECONNECTOR", and "Thinking in Java" Less than a good answer, so I decompressed the JDK's SRC, expanded to open this article, sharing this article, and confirmed that I have no vulnerabilities. Here, take it to study it.

Hashmap can be described as a large tool for JDK, map each Object, and realize the quick access of the "key-value". But what do you do in reality? Before this, you will introduce the properties of the load factor and capacity. Everyone knows that there is actually a HashMap actual capacity to factor * capacity, its default value is 16 × 0.75 = 12; this is very important, it is very impact on efficiency! When the object stored in HashMap exceeds this capacity, HashMap will restructive access tables. This is a big problem, I will slowly introduce it, anyway, if you already know how many objects you want to store, it is best to be able to accept the actual capacity.

Two key methods, PUT and GET: There is such a concept first, and havehmap is declared Map, Cloneable, Serializable interface, and inheriting the AbstractMap class, which is actually mainly its internal class Hashiterator and several other Iterator classes. Realization, of course, there is a very important inheritance of the Entry internal class of Map.Entry, because everyone has source code, everyone is interested in seeing this part, I mainly want to explain the entry of the entry. It contains four properties of Hash, Value, Key, and Next. The source code of the PUT is as follows

Public Object Put (Object Key, Object Value) {Object K = Masknull (Key);

This is the judgment key value is empty, it is not very profound. In fact, if it is empty, it will return a Static Object as a key value, which is why HashMap allows the empty key value.

INT has = hash (k); int i = indexfor (hash, table.length);

This continuous two steps are the most cattle of Hashmap! I have finished sharing, where Hash is HashCode, which is Object Table, is obtained by indexfor's indexFor. TABLE? ? ? Don't be surprised, in fact, Hashmap is not there, it is put it with table. The most cattle is to return indexes correctly with HASH. The Hash algorithm, I contacted the author Doug of JDK, he suggested that "The Art of Programing Vol3" can hate, I have been looking for it before, I can't find it, he like this, I will More anxious, but unfortunately the pocket is empty! ! ! I don't know if you pay attention to the PUT is actually a return method, which will cover the PUT of the same key value and return to the old value! The following method thoroughly illustrates the structure of HashMap, in fact, a list of entry on the corresponding position: for (entry E = Table [i]; E! = Null; E = E.NEXT) {IF (E.hash == Hash && EQ (k, e.key)) {Object OldValue = E.Value; E.Value = value; // Give the new value to the corresponding key value. E.RecordAccess (this); // null method, the rest of the RETURN OLDVALUE; // returns the corresponding old value of the same key value. }}} Modcount ; // Structural changes Adderry (Hash, K, Value, I); // Add new elements, the key! Return null; / / no key value return}

We take the key method to analyze:

Void Addentry (int 6, int bukeet) {table [bucketindex] = new entry (hash, key, value, table [bucketindex]);

Because Hash's algorithm is likely to have the same HASH code as the different key values, such as: key = "33" and key = Object G are all -8901334, which is the index after IndexFor It's all I, so that this entry's next will point to this original Table [i], and then the next one is the same, and the PUT is looped to obtain the old value. Here, have the structure of Hashmap, everyone knows?

IF (size > = threshold) // This Threshold is the actually accommodated amount resize (2 * Table.Length); // Experience the Object Table Reconstruction

The so-called reconstruction is not God, it is to build a twice large Table (I saw someone in other forums said that it is twice, and I cheated it), and then I then INDEXFOR! note! ! This is efficiency! ! If you can make your havehmap don't need to refactor so many times, the efficiency will be greatly improved! It's almost the same here, Get is much simpler than PUT. Everyone knows PUT, GET is also not much. I think that I am suitable for the whole, it is suitable for unique, if everyone's procedure requires special purposes, it is actually very simple. (The author said to me, he also suggested that I use LinkedHashmap, I have seen the source code, Linkhashmap is actually inheriting Hashmap, then Override's corresponding way, interested, Irself LOOKLOOK, build an Object Table, write The corresponding algorithm is OK. For example, like Vector, List is actually very simple, up to more synchronized statement, in fact, if you want to implement it like a vector, insert, you can use an Object Table, Press index to reject, add, etc. If inserted, delete more, you can build two Object Table, then each element contains the next structure, a table save, if you want to insert i, but I already have an element, connect with next, then Size , and Record its location in another table. Source Analysis: Hashmaphashmap is an implementation used in Java New Collection Framework that instead of HashTable. The difference between HashMap and HashTable is that HashMap is not synchronized and allows NULL values. HashTable inherits Dictionary and uses Enumeration, so it is recommended not to use. HashMap statement as follows: public class HashMap extends AbstractMap implements Map, Cloneable, Serializable about AbstractMap: http: //blog.9cbs.net/treeroot/archive/2004/09/20/110343.aspx about Map: http: // blog .9cbs.net / Treeroot / Archive / 2004/09/20 / 110331.aspx About Cloneable: http://blog.9cbs.net/treeroot/archive/2004/09/07/96936.aspx This class is more complicated, here It is only a few ways to analyze several methods, especially the last few internal classes, but it is more simple. static final int DEFAULT_INITIAL_CAPACITY = 16; initial size default static final int MAXIMUM_CAPACITY = 1 << 30; maximum size initialize static final float DEFAULT_LOAD_FACTOR = 0.75f; default load factor transient Entry [] table; Entry length of one type of array, the array is 2 index.

transient int size; number mapped int threshold; final float loadFactor value at the next expansion; load factor transient volatile int modCount; modified frequency public HashMap (int initialCapacity, float loadFactor) {if (initialCapacity <0) throw new IllegalArgumentException ( "Illegal initial capacity:" initialCapacity); if (initialCapacity> MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; if (loadFactor <= 0 || Float.isNaN (loadFactor)) throw new IllegalArgumentException ( "Illegal load factor:" loadFactor); int Capacity = 1; while (capacity >> 14); h = (h << 4); h ^ = (H >>>

10); RETURN H;} There is no way in HashTable, that is, HashTable is a HashCode value of the object directly, but hashMap has improved this algorithm to get a hash value. Static Boolean EQ (Object X, Object Y) {RETURN X == Y || x.equals (y);} static int indexfor (int h, int length) {Return H & (Length-1);} According to Hash The length of the value and array returns to the location of the HASH value in the array, just a simple relationship. Public int size;} public boolean == 0;} public object get (object key) {Object K = Masknull (key); int 6 = hash (k); int i = IndexFor (hash, Table.Length); entry E = Table [I]; while (true) {if (e == null) Return E; if (E.hash == Hash && EQ (K, E.Key)) Return E.VALUE; E = E.NEXT;} This method is to obtain data, first get a hash value, where the NULL value is covered, and the HASH value is corrected by the function hash (). Then calculate the index value of the hash value in the array. If the reference is referenced to NULL, it indicates that this mapping is not present in HashMap. Otherwise, the whole linked list is all over the list. Here is to return, if you are not found, it is traversed to the end of the chain, and returns NULL. The comparison here is like this: E.hash == Hash && EQ (K, E.Key) That is to say, if the HASH is definitely considered non-equal, EQ is shorted, only in the same situation in Hash, only call Equals. method. Now we should understand that if the two objects Equals returns True, their hashcode should the same truth. If two object calls Equals returns True, but hashcode is different, then they think they are not equal in HashMap. Public Boolean Containskey (Object Key) {Object K = Masknull (Key); Int Hash = Hash (K); INT I = IndexFor (Hash, Table.Length); Entry E = Table [I]; While (E! = null ) {IF (E.hash == Hash && EQ (K, E.key)) Return True; E = E.Next;} Return False;} This method is more simple than the above, first find the hash position, and then traverse the whole Link list, return to TRUE if you find it.

Entry GetEntry (Object Key) {Object K = Masknull (Key); Int Hash = Hash (K); INT I = IndexFor (Hash, Table.Length); Entry E = Table [I]; While (E! = Null && ! (E.hash == Hash && EQ (K, E.KEY))) E = E.Next; Return E;} This method returns an Entry node according to the key value, but also get an index position, traverse the link, if not Find back is NULL. Public Object Put (Object Key, Object Value) {Object K = Masknull (Key); Int Hash = Hash (K); INT I = IndexFor (Hash, Table.Length); for (Entry E = Table [i]; E ! = null; e = E.Next) {if (E.hash == Hash && Eq (K, E.key)) {Object OldValue = E.Value; E.Value = Value; E.RecordAccess (this); Return OldValue;}} modcount ; addentry (hash, k, value, i); return null;} First get the Hash index location, if the reference is reference to null, then insert a mapping, return null. If the reference is not null, you must traverse the chain list. If you find the same key, then update the value, return the original value value. If it is not found in traversal, it means that the Key value does not exist or inserts a mapping. If the Hash value is enough to discrete, that is, if the index is not used, then no traverse is a list. Conversely, if the HASH value is not discrete, the extreme, if it is constant, all mappings will be extremely low on this chain. Here is the simplest example, write two different classes as keys inserted into havehmap, and efficiency will be far different.

Class Good {Int i; public good (int i) {this.i = i;} public boolean equals (object o) {Return (o instanceof good) && (this.i == ((good) O) .i). PUBLIC INT HashCode () {RETURN I;}} Class Bad {INT I; Public Good (INT I) {this.i = i;} public boolean equals (object o) {Return (O InstanceOf Good) && (this. i == (good) o) .i)} public int.com} {return 0;}} Execute code: map m1 = new hashmap (); map m2 = new hashmap (); for (int i = 0; I <100; i ) {m1.put (New Good (i), new integer (i)); // The efficiency here is very high} for (int i = 0; i <100; i ) {m2.put (New Bad (i), new integer (i)); // Almost there is almost two very extreme examples, and if you don't know how much difference is performed. Private Void Putforcreate (Object Key, Object Value) {Object K = Masknull (key); int has = hash (k); int = indexfor (hash, table.Length); for (Entry E = Table [i]; e = NULL; E. E.Hash == Hash && EQ (K, E.Key)) {E.Value = Value; Return;}} CreateEntry (Hash, K, Value, i) } void putallForcreate (MAP M) {for (Iterator i = m.enTryset (). Iterator (); I.hasNext ();) {map.entry E = (map.entry) i.next (); PutforcReate E.GetKey (), E.GETVALUE ());}} The above two methods are called by constructor and clone methods. void resize (int newCapacity) {Entry [] oldTable = table; int oldCapacity = oldTable.length; if (size newCapacity) return; Entry [] newTable = new Entry [newCapacity]; transfer (newTable); Table = newTable; threshold = (int);} This method reassocates space when needed, which is equivalent to ArrayList's EnSureCapacity method, but this is more complicated.

Void Transfer (entry [] src = table; int newcapacity = newTable.Length; for (int J = 0; j = threshold) {n = (int) (N / LoadFactor 1); if (N > Maximum_capacity) n = maximum_capacity; int Capacity = Table.Length; while (capacity

public Object remove (Object key) {Entry e = removeEntryForKey (key); return (e == null e:? e.value);} Entry removeEntryForKey (Object key) {Object k = maskNull (key); int hash = hash (k); int I = indexFor (hash, table.Length); entry prev = table [i]; entry E = prev; while (e! = null) {If e == null means there is no entry next = e. Next; if (E.hash == Hash && EQ (K, E.Key)) {modcount ; size ---; if (prev == e) Table [i] = next; The first element of the list is to delete It is best to add an E.NEXT = NULL. Else prev.next = next; existence is not the first element of the list, here is best to add an E.RecordremovAl (this); Return E Prev = E; E = next;} Return E; here is actually return null;} This method is actually not complicated, and it is also traversal chain table. Here is recommended to add an E.NEXT = NULL, it can be changed to IF (prev == e) Table [i] = next; else prev.next = next; E.NEXT = NULL; this sentence is more, which can improve efficiency. Here is a brief explanation: Because e is the deleted node, delete it is actually pointing to its pointer to its back a node. Therefore, E can be used as an object recovered by GC. You can also have a NEXT pointer points to our data, if e is not recycled. And at this time, the node pointing to E.Next has also become useless, but there is a reference (E.Next), so although the next node of E is useless, but can not be used as a GC recycling object, Unless e-first recovery. Although it is not necessarily a big problem, it will at least affect the recovery efficiency of GC. Just like the foreign key references in the database, it is very troublesome to delete it.

Entry RemoveMapping (Object O) {if (! (O instanceof map.entry) Return null; map.entry entry = (map.entry) O; object k = masknull (entry.getKey ()); int hash = hash K); int I = indexfor (haveh, table.Length); entry prev = Table [i]; entry E = prev; while (e! = null) {entry next = E.NEXT; if (E.hash == Hash && e.equals (entry)) {modcount ; size -; if (prev == e) Table [i] = next; else prev.next = next; E.Recordremoval (this); Return E;} prev = E; E = Next;} Return E;} This method is the same as above.

Public void clear () {modcount ; entry tab [] = table; for (int i = 0; i

Object K2 = E.getKey (); if (k1 == k2 || (k1! = Null && k1.equals (k2))) {Object v1 = getValue (); object v2 = E.GetValue (); if ( V1 == V2 || (v1! = null && v1.equals (v2))) Return True;} return false; (Value == NULL? 0: value.hashcode ());} public string toString () {Return getKey () "=" getValue ();} void recordaccess (havehmap m) {} Void Recordremoval (HashMap M) {}} A static internal class Void Addentry (int Haash, Object Key, Object Value, Int BucketIndex) {Table [BucketIndex] = New Entry (Hash, Key, Value, Table [BucketIndex]); if (Size > = Threshold) Resize (2 * Table.Length);

This can be written better understood: Entry oldHead = table [bucketIndex]; Entry newHead = new Entry (hash, key, value, oldHead); table [bucketIndex] = newHead; void createEntry (int hash, Object key, Object value, int bucketIndex) {table [bucketIndex] = new Entry (hash, key, value, table [bucketIndex]); size ;} private abstract class HashIterator implements Iterator {Entry next; int expectedModCount; int index; Entry current; HashIterator () {expectedModCount = modcount; entry [] t = table; int = null; if (size! = 0) {while (i> 0 && (n = t [- i]) == NULL) ;} next = n; index = i;!} public boolean hasNext () {return next = null;} Entry nextEntry () {if (! modCount = expectedModCount) throw new ConcurrentModificationException (); Entry e = next; if (e == null) throw new nosuchelementException (); entry n = E.Next; entry [] t = table; int = index; while (n == null && i> 0) n = t [- -i]; index = i; next = n; return current = e;} public void remove () {if (current == null) throw new IllegalStateException (); if (! modCount = expectedModCount) throw new ConcurrentModificationException (); Object k = current.key; current = null; HashMap.this.removeEntryForKey (k); expectedModCount = modCount;}} private class ValueIterator extends HashIterator {public Object next () {return nextEntry () value.;

}} Private class KeyIterator extends HashIterator {public Object next () {return nextEntry () getKey ();.}} Private class EntryIterator extends HashIterator {public Object next () {return nextEntry ();}} Iterator newKeyIterator () {return new KeyIterator ();} Iterator newValueIterator () {return new ValueIterator ();} Iterator newEntryIterator () {return new EntryIterator ();} private transient Set entrySet = null; public Set keySet () {Set ks = keySet; return ( ! ks = null ks:? (keySet = new keySet ()));} private class keySet extends AbstractSet {public Iterator iterator () {return newKeyIterator ();} public int size () {return size;} public boolean contains ( Object O) {Return Containskey (O);} public boolean remove (Object O) {return.com Collection Values ​​() {Collection vs = VALUES; RETURN (VS! = NULL? VS: (Value s = new Values ​​()));} private class Values ​​extends AbstractCollection {public Iterator iterator () {return newValueIterator ();} public int size () {return size;} public boolean contains (Object o) {return containsValue (o ); Public void clear () {hashmap.this.clear ();}} public set entryset ()} (es! = Null? Es: (entryset = new entryset);} private class EntrySet extends AbstractSet {public Iterator iterator () {return newEntryIterator ();} public boolean contains (Object o) {if (! (o instanceof Map.Entry)) return false; Map.Entry e = (Map.Entry) o; entry Candidate =

GeTENTRY (E.GetKey ()); return caledate! = null && Candidate.equals (e); public boolean remove (Object O) {Return RemoveMapping (o)! = null;} public int size () {Return Size; } public void clear () {HashMap.this.clear ();}} private void writeObject (java.io.ObjectOutputStream s) throws IOException {s.defaultWriteObject (); s.writeInt (table.length); s.writeInt ( Size); for (Iterator i = entryset (). iterator (); I.hasNext ();) {map.entry E = (map.entry) i.next (); s.writeObject (E.GetKey ()) ; s.writeObject (e.getValue ());}} private static final long serialVersionUID = 362498820763181265L; private void readObject (java.io.ObjectInputStream s) throws IOException, ClassNotFoundException {s.defaultReadObject (); int numBuckets = s.readInt (); Table = new entry [Numbuckets]; init (); size = s.readint (); for (int i = 0; for (int i = 0; i

Static final int default_initial_capacity = 16; Default initialization Size Static Final Int Maximum_capacity = 1 << 30; Maximum Initialization Size

Static final float default_load_factor = 0.75f; default add factor

Transient entry [] Table; an array of entry types, an index of the array length 2.

TRANSIENT INT SIZE; Map

INT THRESHOLD; the value of the next expansion

Final float loadfactor; loading factor

TRANSIENT VOLATILE INT MODMOUNT;

public HashMap (int initialCapacity, float loadFactor) {if (initialCapacity <0) throw new IllegalArgumentException ( "Illegal initial capacity:" initialCapacity); if (initialCapacity> MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; if (loadFactor <= 0 || Float. isNaN (loadFactor)) throw new IllegalArgumentException ( "Illegal load factor:" loadFactor); int capacity = 1; while (capacity

Public HashMap (int initialcapacity) {this (Initialcapacity, default_load_factor);

Public hashmap () {this.loadfactor = default_load_factor; threshold = (int)); Note: This should be a mistake! It should be: threshold = (int) (default_initial_capacity * loadingfactor); table = new entry [default_initial_capacity]; init ();

Public HashMap (MAP M) {this (math.max (math.max (m.size () / default_load_fact 1, default_initial_capacity), default_load_factor); PUTALLFORCREATE (M);}

Void init () {}

Static Final Object Null_Key = New Object ();

Static Object Masknull (Object Key) {return (key == null? null_key: key);

Static Object key) {return (key == null_key? null: key);} static int hash (Object x) {int h = x.hashcode (); h = ~ (h << 9); h ^ = (h >>> 14); h = (h << 4); h ^ = (h >>> 10); return h;} There is no method in HashTable, that is, it is directly used in HashTable. The HashCode value of the object, but hashMap made improved use of this algorithm to get a hash value.

Static Boolean EQ (Object X, Object Y) {Return X == Y || x.equals (y);

Static int indexFor (INT H, INT Length) {RETURN H & (LENGTH-1);} Returns the location of the Hash value in array according to the length of the hash value and array, is just a simple relationship.

Public int size () {return size;}

Public Boolean ISempty () {return size == 0;

Public Object Get {Object K = Masknull (key); int has = hash (k); int I = indexfor (hash, table.Length); entry E = Table [i]; while (true) {i (e == NULL) RETURN E; if (E.hash == Hash && EQ (K, E.Key)) Return E.Value; E = E.NEXT;}} This method is to obtain data, first get Hash value, cover the NULL value, and the HASH value is corrected by the function hash (). Then calculate the index value of the hash value in the array. If the reference is referenced to NULL, it indicates that this mapping is not present in HashMap. Otherwise, the whole linked list is all over the list. Here is to return, if you are not found, it is traversed to the end of the chain, and returns NULL. The comparison here is like this: E.hash == Hash && EQ (K, E.Key) That is to say, if the HASH is definitely considered non-equal, EQ is shorted, only in the same situation in Hash, only call Equals. method. Now we should understand that if the two objects Equals returns True, their hashcode should the same truth. If two object calls Equals returns True, but hashcode is different, then they think they are not equal in HashMap.

Public Boolean Containskey (Object Key) {Object K = Masknull (Key); Int Hash = Hash (K); INT I = IndexFor (Hash, Table.Length); Entry E = Table [I]; While (E! = null ) {IF (E.hash == Hash && EQ (K, E.key)) Return True; E = E.Next;} Return False;} This method is more simple than the above, first find the hash position, and then traverse the whole Link list, return to TRUE if you find it. Entry GetEntry (Object Key) {Object K = Masknull (Key); Int Hash = Hash (K); INT I = IndexFor (Hash, Table.Length); Entry E = Table [I]; While (E! = Null && ! (E.hash == Hash && EQ (K, E.KEY))) E = E.Next; Return E;} This method returns an Entry node according to the key value, but also get an index position, traverse the link, if not Find back is NULL.

Public Object Put (Object Key, Object Value) {Object K = Masknull (Key); Int Hash = Hash (K); INT I = IndexFor (Hash, Table.Length); for (Entry E = Table [i]; E ! = null; e = E.Next) {if (E.hash == Hash && Eq (K, E.key)) {Object OldValue = E.Value; E.Value = Value; E.RecordAccess (this); Return OldValue;}} modcount ; addentry (hash, k, value, i); return null;} First get the Hash index location, if the reference is reference to null, then insert a mapping, return null. If the reference is not null, you must traverse the chain list. If you find the same key, then update the value, return the original value value. If it is not found in traversal, it means that the Key value does not exist or inserts a mapping. If the Hash value is enough to discrete, that is, if the index is not used, then no traverse is a list. Conversely, if the HASH value is not discrete, the extreme, if it is constant, all mappings will be extremely low on this chain. Here is the simplest example, write two different classes as keys inserted into havehmap, and efficiency will be far different. Class Good {Int i; public good (int i) {this.i = i;} public boolean equals (object o) {Return (o instanceof good) && (this.i == ((good) O) .i). PUBLIC INT HashCode () {RETURN I;}} Class Bad {INT I; Public Good (INT I) {this.i = i;} public boolean equals (object o) {Return (O InstanceOf Good) && (this. i == (good) o) .i)} public int.com} {return 0;}} Execute code: map m1 = new hashmap (); map m2 = new hashmap (); for (int i = 0; I <100; i ) {m1.put (New Good (i), new integer (i)); // The efficiency here is very high} for (int i = 0; i <100; i ) {m2.put (New Bad (i), new integer (i)); // Almost there is almost two very extreme examples, and if you don't know how much difference is performed.

Private Void Putforcreate (Object Key, Object Value) {Object K = Masknull (key); int has = hash (k); int = indexfor (hash, table.Length); for (Entry E = Table [i]; e = NULL; E. E.Hash == Hash && EQ (K, E.Key)) {E.Value = Value; Return;}} CreateEntry (Hash, K, Value, i) } void putallForcreate (MAP M) {for (Iterator i = m.enTryset (). Iterator (); I.hasNext ();) {map.entry E = (map.entry) i.next (); PutforcReate E.GetKey (), E.GETVALUE ());}} The above two methods are called by constructor and clone methods.

void resize (int newCapacity) {Entry [] oldTable = table; int oldCapacity = oldTable.length; if (size newCapacity) return; Entry [] newTable = new Entry [newCapacity]; transfer (newTable); Table = newTable; threshold = (int);} This method reassocates space when needed, which is equivalent to ArrayList's EnSureCapacity method, but this is more complicated.

Void Transfer (entry [] src = table; int newcapacity = newTable.Length; for (int J = 0; j

Public void Putall (MAP T) {INT N = T.Size (); if (n == 0) Return; if (n> = threshold) {n = (int) (N / LoadFactor 1); if (N > Maximum_capacity) n = maximum_capacity; int Capacity = Table.Length; while (capacity

Entry RemoventryForKey (Object Key) {Object K = Masknull (key); int has = hash (k); int = indexfor (hash, table.Length); entry prev = table [i]; entry E = prev; while e! = null) {If e == null means there is no entry next = E.Next; if (E.hash == Hash && EQ (K, E.Key)) {modcount ; size--; if (prev = = E) Table [i] = next; the first element of the list is to delete, here is best to add an E.NEXT = NULL. Else prev.next = next; existence is not the first element of the list, here It is best to add E.Next = null. E.Recordremoval (this); return e;} prev = E; E = next;} return e; here is actually return null;} This method is not complicated, and the traversal table Here, it is recommended to add an E.Next = NULL, which can be changed to if (prev == e) table [i] = next; else prev.next = next; E.NEXT = NULL; this sentence is more, it can improve efficiency . Here is a brief explanation: Because e is the deleted node, delete it is actually pointing to its pointer to its back a node. Therefore, E can be used as an object recovered by GC. You can also have a NEXT pointer points to our data, if e is not recycled. And at this time, the node pointing to E.Next has also become useless, but there is a reference (E.Next), so although the next node of E is useless, but can not be used as a GC recycling object, Unless e-first recovery. Although it is not necessarily a big problem, it will at least affect the recovery efficiency of GC. Just like the foreign key references in the database, it is very troublesome to delete it.

Entry RemoveMapping (Object O) {if (! (O instanceof map.entry) Return null; map.entry entry = (map.entry) O; object k = masknull (entry.getKey ()); int hash = hash K); int I = indexfor (haveh, table.Length); entry prev = Table [i]; entry E = prev; while (e! = null) {entry next = E.NEXT; if (E.hash == Hash && e.equals (entry)) {modcount ; size -; if (prev == e) Table [i] = next; else prev.next = next; E.Recordremoval (this); Return E;} prev = E; E = Next;} Return E;} This method is the same as above. Public void clear () {modcount ; entry tab [] = table; for (int i = 0; i

Public Boolean ContaSvalue ({if (value == null) Return ContainSnullValue (); entry tab [] = table; for (int i = 0; i

Private Boolean ContainSnullValue () {entry Tab [] = Table; for (int i = 0; i

public Object clone () {HashMap result = null; try {result = (HashMap) super.clone ();} catch (CloneNotSupportedException e) {// assert false;} result.table = new Entry [table.length]; result .entrySet = null; result.modCount = 0; result.size = 0; result.init (); result.putAllForCreate (this); return result;} static class Entry implements Map.Entry {final Object key; Object value; final INTHESH; Entry Next; Entry (int h, object k, object v, entry n) {value = v; next = n; key = k; hash = h;} public object getKey () {Return unmasknull (key); } public Object getValue () {return value;} public Object setValue (Object newValue) {Object oldValue = value; value = newValue; return oldValue;!} public boolean equals (Object o) {if ((o instanceof Map.Entry) Return False; map.entry E = (map.entry) O; Object K1 = getKey (); Object K2 = E.GetKey (); if (k1 == k2 || (k1! = Nu LL && K1.Equals (k2))) {Object v1 = getValue (); object v2 = E.GETVALUE (); if (v1 == V2 || (v1! = null && v1.equals (v2))) Return True;} returnaf ()} public int 6code () {return (key == null_key? 0: key.hashcode ()) ^ (value == null? 0: value.hashcode ());} public string toString () {Return getKey () "=" getValue ();} void recordaccess (HashMap M) {} void recordremoval (havehmap m) {}} A static internal class

void addEntry (int hash, Object key, Object value, int bucketIndex) {table [bucketIndex] = new Entry (hash, key, value, table [bucketIndex]); if (size > = threshold) resize (2 * table.length ); Note this method, insert the head of the same table. This can be written better understood: Entry oldHead = table [bucketIndex]; Entry newHead = new Entry (hash, key, value, oldHead); table [bucketIndex] = newHead; void createEntry (int hash, Object key, Object value, int BucketIndex) {Table [BucketIndex] = New Entry (Hash, Key, Value, Table [BucketIndex]); SIZE ;}

private abstract class HashIterator implements Iterator {Entry next; int expectedModCount; int index; Entry current; HashIterator () {expectedModCount = modCount; Entry [] t = table; int i = t.length; Entry n = null; if (size! = 0) {While (n = t [n =]) == null);} next = n; index = i;} public boolean Hasnext () {Return next! = Null;} entry nextentry () {if (! modCount = expectedModCount) throw new ConcurrentModificationException (); Entry e = next; if (e == null) throw new NoSuchElementException (); Entry n = e.next; Entry [] t = table; int i = index; while (n == NULL && I> 0) n = t [- i]; index = i; next = n; return current = e;} public void remove () {if (current == null) Throw new IllegalStateException (); if (MODCOUNT! = Expectedmodcount) throw new concurrentmodificationException (); Object K = Current.Key; Cu Rrent = null; hashmap.this.removeentryforKey (k); expectedmodcount = modcount;} }.com.

Private class keyiterator extends hashiterator {public object next () {return next (). getKey ();}}

Private class entryiterator extends hashiterator {public object next () {return next ();}}

Iterator newkeyiterator () {return new keyiterator ();

Iterator newvalueiterator () {return new valueiterator ();}

Iterator newntryiterator () {return new entryiterator ();} private transient set entryset = NULL

Public set keyset () {set ks = keyset; return (ks! = null? ks: (keyset = new keyset));}

private class KeySet extends AbstractSet {public Iterator iterator () {return newKeyIterator ();} public int size () {return size;} public boolean contains (Object o) {return containsKey (o);} public boolean remove (Object o) {Return HashMap.This.RemoventryForKey (o)! = Null;} public void clear () {hashmap.this.clear ();}}

Public Collection Values ​​() {Collection VS = VALUES; RETURN (VS! = NULL? VS: (VALUES = New Values ​​()));}

private class Values ​​extends AbstractCollection {public Iterator iterator () {return newValueIterator ();} public int size () {return size;} public boolean contains (Object o) {return containsValue (o);} public void clear () {HashMap .THIS.CLEAR ();}}

Public set entryset () {set es = entryset; return (es! = null? es: (entryset = new entryset));

private class EntrySet extends AbstractSet {public Iterator iterator () {return newEntryIterator ();} public boolean contains (Object o) {if (! (o instanceof Map.Entry)) return false; Map.Entry e = (Map.Entry) O; entry candidate = getentry (E.GetKey ()); return Candidate! = Null && Candidate.equals (e);} public boolean remove (Object O) {Return RemoveMapping (o)! = null;} public int size ) {Return size;} public void clear () {hashmap.this.clear ();}}

private void writeObject (java.io.ObjectOutputStream s) throws IOException {s.defaultWriteObject (); s.writeInt (table.length); s.writeInt (size); for (Iterator i = entrySet () iterator ();. i .hasNext (); {map.entry E = (map.entry) i.next (); s.writeObject (E.GetKey ()); s.writeObject (E.GetValue ());}} private static final Long serialversionuid = 362498820763181265L;

private void readObject (java.io.ObjectInputStream s) throws IOException, ClassNotFoundException {s.defaultReadObject (); int numBuckets = s.readInt (); table = new Entry [numBuckets]; init (); size = s.readInt () ; for (int i = 0; I

INT Capacity () {Return Table.Length;} Float LoadFactor () {Return LoadFactor;

Hashmap can be described as a large tool for JDK, map each Object, and realize the quick access of the "key-value". But what do you do in reality? Before this, you will introduce the properties of the load factor and capacity. Everyone knows that there is actually a HashMap actual capacity to factor * capacity, its default value is 16 × 0.75 = 12; this is very important, it is very impact on efficiency! When the object stored in HashMap exceeds this capacity, HashMap will restructive access tables. This is a big problem, I will slowly introduce it, anyway, if you already know how many objects you want to store, it is best to be able to accept the actual capacity.

Two key methods, PUT and GET: There is such a concept first, and havehmap is declared Map, Cloneable, Serializable interface, and inheriting the AbstractMap class, which is actually mainly its internal class Hashiterator and several other Iterator classes. Realization, of course, there is a very important inheritance of the Entry internal class of Map.Entry, because everyone has source code, everyone is interested in seeing this part, I mainly want to explain the entry of the entry. It contains four properties of Hash, Value, Key, and Next. The source code of the PUT is as follows

Public Object Put (Object Key, Object Value) {Object K = Masknull (Key);

This is the judgment key value is empty, it is not very profound. In fact, if it is empty, it will return a Static Object as a key value, which is why HashMap allows the empty key value. INT has = hash (k); int i = indexfor (hash, table.length);

This continuous two steps are the most cattle of Hashmap! I have finished sharing, where Hash is HashCode, which is Object Table, is obtained by indexfor's indexFor. TABLE? ? ? Don't be surprised, in fact, Hashmap is not there, it is put it with table. The most cattle is to return indexes correctly with HASH. The Hash algorithm, I contacted the author Doug of JDK, he suggested that "The Art of Programing Vol3" can hate, I have been looking for it before, I can't find it, he like this, I will More anxious, but unfortunately the pocket is empty! ! ! I don't know if you pay attention to the PUT is actually a return method, which will cover the PUT of the same key value and return to the old value! The following method thoroughly illustrates the structure of HashMap, in fact, a list of entry in the corresponding position:

For (Entry E = Table [I]; E! = NULL; E = E.Next) {IF (E.hash == Hash && EQ (K, E.Key) {Object OldValue = E.Value; E. Value = value; // Give the new value to the corresponding key value. E.RecordAccess (this); // null method, the rest of the RETURN OLDVALUE; // returns the corresponding old value of the same key value. }}} Modcount ; // Structural changes Adderry (Hash, K, Value, I); // Add new elements, the key! Return null; / / no key value return}

We take the key method to analyze:

Void Addentry (int 6, int bukeet) {table [bucketindex] = new entry (hash, key, value, table [bucketindex]);

Because Hash's algorithm is likely to have the same HASH code as the different key values, such as: key = "33" and key = Object G are all -8901334, which is the index after IndexFor It's all I, so that this entry's next will point to this original Table [i], and then the next one is the same, and the PUT is looped to obtain the old value. Here, have the structure of Hashmap, everyone knows?

IF (size > = threshold) // This Threshold is the actually accommodated amount resize (2 * Table.Length); // Experience the Object Table Reconstruction

The so-called reconstruction is not God, it is to build a twice large Table (I saw someone in other forums said that it is twice, and I cheated it), and then I then INDEXFOR! note! ! This is efficiency! ! If you can make your havehmap don't need to refactor so many times, the efficiency will be greatly improved! It's almost the same here, Get is much simpler than PUT. Everyone knows PUT, GET is also not much. I think that I am suitable for the whole, it is suitable for unique, if everyone's procedure requires special purposes, it is actually very simple. (The author said to me, he also suggested that I use LinkedHashmap, I have seen the source code, Linkhashmap is actually inheriting Hashmap, then Override's corresponding way, interested, Irself LOOKLOOK, build an Object Table, write The corresponding algorithm is OK. For example, like Vector, List is actually very simple, up to more synchronized statement, in fact, if you want to implement it like a vector, insert, you can use an Object Table, Press index to reject, add, etc. If inserted, delete more, you can build two Object Table, then each element contains the next structure, a table save, if you want to insert i, but I already have an element, connect with next, then Size , and Record its location in another table. Source Analysis: Hashmaphashmap is an implementation used in Java New Collection Framework that instead of HashTable. The difference between HashMap and HashTable is that HashMap is not synchronized and allows NULL values. HashTable inherits Dictionary and uses Enumeration, so it is recommended not to use. HashMap statement as follows: public class HashMap extends AbstractMap implements Map, Cloneable, Serializable about AbstractMap: http: //blog.9cbs.net/treeroot/archive/2004/09/20/110343.aspx about Map: http: // blog .9cbs.net / Treeroot / Archive / 2004/09/20 / 110331.aspx About Cloneable: http://blog.9cbs.net/treeroot/archive/2004/09/07/96936.aspx This class is more complicated, here It is only a few ways to analyze several methods, especially the last few internal classes, but it is more simple. static final int DEFAULT_INITIAL_CAPACITY = 16; initial size default static final int MAXIMUM_CAPACITY = 1 << 30; maximum size initialize static final float DEFAULT_LOAD_FACTOR = 0.75f; default load factor transient Entry [] table; Entry length of one type of array, the array is 2 index.

transient int size; number mapped int threshold; final float loadFactor value at the next expansion; load factor transient volatile int modCount; modified frequency public HashMap (int initialCapacity, float loadFactor) {if (initialCapacity <0) throw new IllegalArgumentException ( "Illegal initial capacity:" initialCapacity); if (initialCapacity> MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; if (loadFactor <= 0 || Float.isNaN (loadFactor)) throw new IllegalArgumentException ( "Illegal load factor:" loadFactor); int Capacity = 1; while (capacity >> 14); h = (h << 4); h ^ = (H >>>

10); RETURN H;} There is no way in HashTable, that is, HashTable is a HashCode value of the object directly, but hashMap has improved this algorithm to get a hash value. Static Boolean EQ (Object X, Object Y) {RETURN X == Y || x.equals (y);} static int indexfor (int h, int length) {Return H & (Length-1);} According to Hash The length of the value and array returns to the location of the HASH value in the array, just a simple relationship. Public int size;} public boolean == 0;} public object get (object key) {Object K = Masknull (key); int 6 = hash (k); int i = IndexFor (hash, Table.Length); entry E = Table [I]; while (true) {if (e == null) Return E; if (E.hash == Hash && EQ (K, E.Key)) Return E.VALUE; E = E.NEXT;} This method is to obtain data, first get a hash value, where the NULL value is covered, and the HASH value is corrected by the function hash (). Then calculate the index value of the hash value in the array. If the reference is referenced to NULL, it indicates that this mapping is not present in HashMap. Otherwise, the whole linked list is all over the list. Here is to return, if you are not found, it is traversed to the end of the chain, and returns NULL. The comparison here is like this: E.hash == Hash && EQ (K, E.Key) That is to say, if the HASH is definitely considered non-equal, EQ is shorted, only in the same situation in Hash, only call Equals. method. Now we should understand that if the two objects Equals returns True, their hashcode should the same truth. If two object calls Equals returns True, but hashcode is different, then they think they are not equal in HashMap. Public Boolean Containskey (Object Key) {Object K = Masknull (Key); Int Hash = Hash (K); INT I = IndexFor (Hash, Table.Length); Entry E = Table [I]; While (E! = null ) {IF (E.hash == Hash && EQ (K, E.key)) Return True; E = E.Next;} Return False;} This method is more simple than the above, first find the hash position, and then traverse the whole Link list, return to TRUE if you find it.

Entry GetEntry (Object Key) {Object K = Masknull (Key); Int Hash = Hash (K); INT I = IndexFor (Hash, Table.Length); Entry E = Table [I]; While (E! = Null && ! (E.hash == Hash && EQ (K, E.KEY))) E = E.Next; Return E;} This method returns an Entry node according to the key value, but also get an index position, traverse the link, if not Find back is NULL. Public Object Put (Object Key, Object Value) {Object K = Masknull (Key); Int Hash = Hash (K); INT I = IndexFor (Hash, Table.Length); for (Entry E = Table [i]; E ! = null; e = E.Next) {if (E.hash == Hash && Eq (K, E.key)) {Object OldValue = E.Value; E.Value = Value; E.RecordAccess (this); Return OldValue;}} modcount ; addentry (hash, k, value, i); return null;} First get the Hash index location, if the reference is reference to null, then insert a mapping, return null. If the reference is not null, you must traverse the chain list. If you find the same key, then update the value, return the original value value. If it is not found in traversal, it means that the Key value does not exist or inserts a mapping. If the Hash value is enough to discrete, that is, if the index is not used, then no traverse is a list. Conversely, if the HASH value is not discrete, the extreme, if it is constant, all mappings will be extremely low on this chain. Here is the simplest example, write two different classes as keys inserted into havehmap, and efficiency will be far different.

Class Good {Int i; public good (int i) {this.i = i;} public boolean equals (object o) {Return (o instanceof good) && (this.i == ((good) O) .i). PUBLIC INT HashCode () {RETURN I;}} Class Bad {INT I; Public Good (INT I) {this.i = i;} public boolean equals (object o) {Return (O InstanceOf Good) && (this. i == (good) o) .i)} public int.com} {return 0;}} Execute code: map m1 = new hashmap (); map m2 = new hashmap (); for (int i = 0; I <100; i ) {m1.put (New Good (i), new integer (i)); // The efficiency here is very high} for (int i = 0; i <100; i ) {m2.put (New Bad (i), new integer (i)); // Almost there is almost two very extreme examples, and if you don't know how much difference is performed. Private Void Putforcreate (Object Key, Object Value) {Object K = Masknull (key); int has = hash (k); int = indexfor (hash, table.Length); for (Entry E = Table [i]; e = NULL; E. E.Hash == Hash && EQ (K, E.Key)) {E.Value = Value; Return;}} CreateEntry (Hash, K, Value, i) } void putallForcreate (MAP M) {for (Iterator i = m.enTryset (). Iterator (); I.hasNext ();) {map.entry E = (map.entry) i.next (); PutforcReate E.GetKey (), E.GETVALUE ());}} The above two methods are called by constructor and clone methods. void resize (int newCapacity) {Entry [] oldTable = table; int oldCapacity = oldTable.length; if (size newCapacity) return; Entry [] newTable = new Entry [newCapacity]; transfer (newTable); Table = newTable; threshold = (int);} This method reassocates space when needed, which is equivalent to ArrayList's EnSureCapacity method, but this is more complicated.

Void Transfer (entry [] src = table; int newcapacity = newTable.Length; for (int J = 0; j = threshold) {n = (int) (N / LoadFactor 1); if (N > Maximum_capacity) n = maximum_capacity; int Capacity = Table.Length; while (capacity

public Object remove (Object key) {Entry e = removeEntryForKey (key); return (e == null e:? e.value);} Entry removeEntryForKey (Object key) {Object k = maskNull (key); int hash = hash (k); int I = indexFor (hash, table.Length); entry prev = table [i]; entry E = prev; while (e! = null) {If e == null means there is no entry next = e. Next; if (E.hash == Hash && EQ (K, E.Key)) {modcount ; size ---; if (prev == e) Table [i] = next; The first element of the list is to delete It is best to add an E.NEXT = NULL. Else prev.next = next; existence is not the first element of the list, here is best to add an E.RecordremovAl (this); Return E Prev = E; E = next;} Return E; here is actually return null;} This method is actually not complicated, and it is also traversal chain table. Here is recommended to add an E.NEXT = NULL, it can be changed to IF (prev == e) Table [i] = next; else prev.next = next; E.NEXT = NULL; this sentence is more, which can improve efficiency. Here is a brief explanation: Because e is the deleted node, delete it is actually pointing to its pointer to its back a node. Therefore, E can be used as an object recovered by GC. You can also have a NEXT pointer points to our data, if e is not recycled. And at this time, the node pointing to E.Next has also become useless, but there is a reference (E.Next), so although the next node of E is useless, but can not be used as a GC recycling object, Unless e-first recovery. Although it is not necessarily a big problem, it will at least affect the recovery efficiency of GC. Just like the foreign key references in the database, it is very troublesome to delete it.

Entry RemoveMapping (Object O) {if (! (O instanceof map.entry) Return null; map.entry entry = (map.entry) O; object k = masknull (entry.getKey ()); int hash = hash K); int I = indexfor (haveh, table.Length); entry prev = Table [i]; entry E = prev; while (e! = null) {entry next = E.NEXT; if (E.hash == Hash && e.equals (entry)) {modcount ; size -; if (prev == e) Table [i] = next; else prev.next = next; E.Recordremoval (this); Return E;} prev = E; E = Next;} Return E;} This method is the same as above.

Public void clear () {modcount ; entry tab [] = table; for (int i = 0; i

Object K2 = E.getKey (); if (k1 == k2 || (k1! = Null && k1.equals (k2))) {Object v1 = getValue (); object v2 = E.GetValue (); if ( V1 == V2 || (v1! = null && v1.equals (v2))) Return True;} return false; (Value == NULL? 0: value.hashcode ());} public string toString () {Return getKey () "=" getValue ();} void recordaccess (havehmap m) {} Void Recordremoval (HashMap M) {}} A static internal class Void Addentry (int Haash, Object Key, Object Value, Int BucketIndex) {Table [BucketIndex] = New Entry (Hash, Key, Value, Table [BucketIndex]); if (Size > = Threshold) Resize (2 * Table.Length);

This can be written better understood: Entry oldHead = table [bucketIndex]; Entry newHead = new Entry (hash, key, value, oldHead); table [bucketIndex] = newHead; void createEntry (int hash, Object key, Object value, int bucketIndex) {table [bucketIndex] = new Entry (hash, key, value, table [bucketIndex]); size ;} private abstract class HashIterator implements Iterator {Entry next; int expectedModCount; int index; Entry current; HashIterator () {expectedModCount = modcount; entry [] t = table; int = null; if (size! = 0) {while (i> 0 && (n = t [- i]) == NULL) ;} next = n; index = i;!} public boolean hasNext () {return next = null;} Entry nextEntry () {if (! modCount = expectedModCount) throw new ConcurrentModificationException (); Entry e = next; if (e == null) throw new nosuchelementException (); entry n = E.Next; entry [] t = table; int = index; while (n == null && i> 0) n = t [- -i]; index = i; next = n; return current = e;} public void remove () {if (current == null) throw new IllegalStateException (); if (! modCount = expectedModCount) throw new ConcurrentModificationException (); Object k = current.key; current = null; HashMap.this.removeEntryForKey (k); expectedModCount = modCount;}} private class ValueIterator extends HashIterator {public Object next () {return nextEntry () value.;

}} Private class KeyIterator extends HashIterator {public Object next () {return nextEntry () getKey ();.}} Private class EntryIterator extends HashIterator {public Object next () {return nextEntry ();}} Iterator newKeyIterator () {return new KeyIterator ();} Iterator newValueIterator () {return new ValueIterator ();} Iterator newEntryIterator () {return new EntryIterator ();} private transient Set entrySet = null; public Set keySet () {Set ks = keySet; return ( ! ks = null ks:? (keySet = new keySet ()));} private class keySet extends AbstractSet {public Iterator iterator () {return newKeyIterator ();} public int size () {return size;} public boolean contains ( Object O) {Return Containskey (O);} public boolean remove (Object O) {return.com Collection Values ​​() {Collection vs = VALUES; RETURN (VS! = NULL? VS: (Value s = new Values ​​()));} private class Values ​​extends AbstractCollection {public Iterator iterator () {return newValueIterator ();} public int size () {return size;} public boolean contains (Object o) {return containsValue (o ); Public void clear () {hashmap.this.clear ();}} public set entryset ()} (es! = Null? Es: (entryset = new entryset);} private class EntrySet extends AbstractSet {public Iterator iterator () {return newEntryIterator ();} public boolean contains (Object o) {if (! (o instanceof Map.Entry)) return false; Map.Entry e = (Map.Entry) o; entry Candidate =

GeTENTRY (E.GetKey ()); return caledate! = null && Candidate.equals (e); public boolean remove (Object O) {Return RemoveMapping (o)! = null;} public int size () {Return Size; } public void clear () {HashMap.this.clear ();}} private void writeObject (java.io.ObjectOutputStream s) throws IOException {s.defaultWriteObject (); s.writeInt (table.length); s.writeInt ( Size); for (Iterator i = entryset (). iterator (); I.hasNext ();) {map.entry E = (map.entry) i.next (); s.writeObject (E.GetKey ()) ; s.writeObject (e.getValue ());}} private static final long serialVersionUID = 362498820763181265L; private void readObject (java.io.ObjectInputStream s) throws IOException, ClassNotFoundException {s.defaultReadObject (); int numBuckets = s.readInt (); Table = new entry [Numbuckets]; init (); size = s.readint (); for (int i = 0; for (int i = 0; i

Static final int default_initial_capacity = 16; Default initialization Size Static Final Int Maximum_capacity = 1 << 30; Maximum Initialization Size

Static final float default_load_factor = 0.75f; default add factor

Transient entry [] Table; an array of entry types, an index of the array length 2.

TRANSIENT INT SIZE; Map of Map

INT THRESHOLD; the value of the next expansion

Final float loadfactor; loading factor

TRANSIENT VOLATILE INT MODMOUNT;

public HashMap (int initialCapacity, float loadFactor) {if (initialCapacity <0) throw new IllegalArgumentException ( "Illegal initial capacity:" initialCapacity); if (initialCapacity> MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; if (loadFactor <= 0 || Float. isNaN (loadFactor)) throw new IllegalArgumentException ( "Illegal load factor:" loadFactor); int capacity = 1; while (capacity

Public HashMap (int initialcapacity) {this (Initialcapacity, default_load_factor);

Public hashmap () {this.loadfactor = default_load_factor; threshold = (int)); Note: This should be a mistake! It should be: threshold = (int) (default_initial_capacity * loadingfactor); table = new entry [default_initial_capacity]; init ();

Public HashMap (MAP M) {this (math.max (math.max (m.size () / default_load_fact 1, default_initial_capacity), default_load_factor); PUTALLFORCREATE (M);}

Void init () {}

Static Final Object Null_Key = New Object ();

Static Object Masknull (Object Key) {return (key == null? null_key: key);

Static Object key) {return (key == null_key? null: key);} static int hash (Object x) {int h = x.hashcode (); h = ~ (h << 9); h ^ = (h >>> 14); h = (h << 4); h ^ = (h >>> 10); return h;} There is no method in HashTable, that is, it is directly used in HashTable. The HashCode value of the object, but hashMap made improved use of this algorithm to get a hash value.

Static Boolean EQ (Object X, Object Y) {Return X == Y || x.equals (y);

Static int indexFor (INT H, INT Length) {RETURN H & (LENGTH-1);} Returns the location of the Hash value in array according to the length of the hash value and array, is just a simple relationship.

Public int size () {return size;}

Public Boolean ISempty () {return size == 0;

Public Object Get {Object K = Masknull (key); int has = hash (k); int I = indexfor (hash, table.Length); entry E = Table [i]; while (true) {i (e == NULL) RETURN E; if (E.hash == Hash && EQ (K, E.Key)) Return E.Value; E = E.NEXT;}} This method is to obtain data, first get Hash value, cover the NULL value, and the HASH value is corrected by the function hash (). Then calculate the index value of the hash value in the array. If the reference is referenced to NULL, it indicates that this mapping is not present in HashMap. Otherwise, the whole linked list is all over the list. Here is to return, if you are not found, it is traversed to the end of the chain, and returns NULL. The comparison here is like this: E.hash == Hash && EQ (K, E.Key) That is to say, if the HASH is definitely considered non-equal, EQ is shorted, only in the same situation in Hash, only call Equals. method. Now we should understand that if the two objects Equals returns True, their hashcode should the same truth. If two object calls Equals returns True, but hashcode is different, then they think they are not equal in HashMap.

Public Boolean Containskey (Object Key) {Object K = Masknull (Key); Int Hash = Hash (K); INT I = IndexFor (Hash, Table.Length); Entry E = Table [I]; While (E! = null ) {IF (E.hash == Hash && EQ (K, E.key)) Return True; E = E.Next;} Return False;} This method is more simple than the above, first find the hash position, and then traverse the whole Link list, return to TRUE if you find it. Entry GetEntry (Object Key) {Object K = Masknull (Key); Int Hash = Hash (K); INT I = IndexFor (Hash, Table.Length); Entry E = Table [I]; While (E! = Null && ! (E.hash == Hash && EQ (K, E.KEY))) E = E.Next; Return E;} This method returns an Entry node according to the key value, but also get an index position, traverse the link, if not Find back is NULL.

Public Object Put (Object Key, Object Value) {Object K = Masknull (Key); Int Hash = Hash (K); INT I = IndexFor (Hash, Table.Length); for (Entry E = Table [i]; E ! = null; e = E.Next) {if (E.hash == Hash && Eq (K, E.key)) {Object OldValue = E.Value; E.Value = Value; E.RecordAccess (this); Return OldValue;}} modcount ; addentry (hash, k, value, i); return null;} First get the Hash index location, if the reference is reference to null, then insert a mapping, return null. If the reference is not null, you must traverse the chain list. If you find the same key, then update the value, return the original value value. If it is not found in traversal, it means that the Key value does not exist or inserts a mapping. If the Hash value is enough to discrete, that is, if the index is not used, then no traverse is a list. Conversely, if the HASH value is not discrete, the extreme, if it is constant, all mappings will be extremely low on this chain. Here is the simplest example, write two different classes as keys inserted into havehmap, and efficiency will be far different. Class Good {Int i; public good (int i) {this.i = i;} public boolean equals (object o) {Return (o instanceof good) && (this.i == ((good) O) .i). PUBLIC INT HashCode () {RETURN I;}} Class Bad {INT I; Public Good (INT I) {this.i = i;} public boolean equals (object o) {Return (O InstanceOf Good) && (this. i == (good) o) .i)} public int.com} {return 0;}} Execute code: map m1 = new hashmap (); map m2 = new hashmap (); for (int i = 0; I <100; i ) {m1.put (New Good (i), new integer (i)); // The efficiency here is very high} for (int i = 0; i <100; i ) {m2.put (New Bad (i), new integer (i)); // Almost there is almost two very extreme examples, and if you don't know how much difference is performed.

Private Void Putforcreate (Object Key, Object Value) {Object K = Masknull (key); int has = hash (k); int = indexfor (hash, table.Length); for (Entry E = Table [i]; e = NULL; E. E.Hash == Hash && EQ (K, E.Key)) {E.Value = Value; Return;}} CreateEntry (Hash, K, Value, i) } void putallForcreate (MAP M) {for (Iterator i = m.enTryset (). Iterator (); I.hasNext ();) {map.entry E = (map.entry) i.next (); PutforcReate E.GetKey (), E.GETVALUE ());}} The above two methods are called by constructor and clone methods.

void resize (int newCapacity) {Entry [] oldTable = table; int oldCapacity = oldTable.length; if (size newCapacity) return; Entry [] newTable = new Entry [newCapacity]; transfer (newTable); Table = newTable; threshold = (int);} This method reassocates space when needed, which is equivalent to ArrayList's EnSureCapacity method, but this is more complicated.

Void Transfer (entry [] src = table; int newcapacity = newTable.Length; for (int J = 0; j

Public void Putall (MAP T) {INT N = T.Size (); if (n == 0) Return; if (n> = threshold) {n = (int) (N / LoadFactor 1); if (N > Maximum_capacity) n = maximum_capacity; int Capacity = Table.Length; while (capacity

Entry RemoventryForKey (Object Key) {Object K = Masknull (key); int has = hash (k); int = indexfor (hash, table.Length); entry prev = table [i]; entry E = prev; while e! = null) {If e == null means there is no entry next = E.Next; if (E.hash == Hash && EQ (K, E.Key)) {modcount ; size--; if (prev = = E) Table [i] = next; the first element of the list is to delete, here is best to add an E.NEXT = NULL. Else prev.next = next; existence is not the first element of the list, here It is best to add E.Next = null. E.Recordremoval (this); return e;} prev = E; E = next;} return e; here is actually return null;} This method is not complicated, and the traversal table Here, it is recommended to add an E.Next = NULL, which can be changed to if (prev == e) table [i] = next; else prev.next = next; E.NEXT = NULL; this sentence is more, it can improve efficiency . Here is a brief explanation: Because e is the deleted node, delete it is actually pointing to its pointer to its back a node. Therefore, E can be used as an object recovered by GC. You can also have a NEXT pointer points to our data, if e is not recycled. And at this time, the node pointing to E.Next has also become useless, but there is a reference (E.Next), so although the next node of E is useless, but can not be used as a GC recycling object, Unless e-first recovery. Although it is not necessarily a big problem, it will at least affect the recovery efficiency of GC. Just like the foreign key references in the database, it is very troublesome to delete it.

Entry RemoveMapping (Object O) {if (! (O instanceof map.entry) Return null; map.entry entry = (map.entry) O; object k = masknull (entry.getKey ()); int hash = hash K); int I = indexfor (haveh, table.Length); entry prev = Table [i]; entry E = prev; while (e! = null) {entry next = E.NEXT; if (E.hash == Hash && e.equals (entry)) {modcount ; size -; if (prev == e) Table [i] = next; else prev.next = next; E.Recordremoval (this); Return E;} prev = E; E = Next;} Return E;} This method is the same as above. Public void clear () {modcount ; entry tab [] = table; for (int i = 0; i

Public Boolean ContaSvalue ({if (value == null) Return ContainSnullValue (); entry tab [] = table; for (int i = 0; i

Private Boolean ContainSnullValue () {entry Tab [] = Table; for (int i = 0; i

public Object clone () {HashMap result = null; try {result = (HashMap) super.clone ();} catch (CloneNotSupportedException e) {// assert false;} result.table = new Entry [table.length]; result .entrySet = null; result.modCount = 0; result.size = 0; result.init (); result.putAllForCreate (this); return result;} static class Entry implements Map.Entry {final Object key; Object value; final INTHESH; Entry Next; Entry (int h, object k, object v, entry n) {value = v; next = n; key = k; hash = h;} public object getKey () {Return unmasknull (key); } public Object getValue () {return value;} public Object setValue (Object newValue) {Object oldValue = value; value = newValue; return oldValue;!} public boolean equals (Object o) {if ((o instanceof Map.Entry) Return False; map.entry E = (map.entry) O; Object K1 = getKey (); Object K2 = E.GetKey (); if (k1 == k2 || (k1! = Nu LL && K1.Equals (k2))) {Object v1 = getValue (); object v2 = E.GETVALUE (); if (v1 == V2 || (v1! = null && v1.equals (v2))) Return True;} returnaf ()} public int 6code () {return (key == null_key? 0: key.hashcode ()) ^ (value == null? 0: value.hashcode ());} public string toString () {Return getKey () "=" getValue ();} void recordaccess (HashMap M) {} void recordremoval (havehmap m) {}} A static internal class

void addEntry (int hash, Object key, Object value, int bucketIndex) {table [bucketIndex] = new Entry (hash, key, value, table [bucketIndex]); if (size > = threshold) resize (2 * table.length ); Note this method, insert the head of the same table. This can be written better understood: Entry oldHead = table [bucketIndex]; Entry newHead = new Entry (hash, key, value, oldHead); table [bucketIndex] = newHead; void createEntry (int hash, Object key, Object value, int BucketIndex) {Table [BucketIndex] = New Entry (Hash, Key, Value, Table [BucketIndex]); SIZE ;}

private abstract class HashIterator implements Iterator {Entry next; int expectedModCount; int index; Entry current; HashIterator () {expectedModCount = modCount; Entry [] t = table; int i = t.length; Entry n = null; if (size! = 0) {While (n = t [n =]) == null);} next = n; index = i;} public boolean Hasnext () {Return next! = Null;} entry nextentry () {if (! modCount = expectedModCount) throw new ConcurrentModificationException (); Entry e = next; if (e == null) throw new NoSuchElementException (); Entry n = e.next; Entry [] t = table; int i = index; while (n == NULL && I> 0) n = t [- i]; index = i; next = n; return current = e;} public void remove () {if (current == null) Throw new IllegalStateException (); if (MODCOUNT! = Expectedmodcount) throw new concurrentmodificationException (); Object K = Current.Key; Cu Rrent = null; hashmap.this.removeentryforKey (k); expectedmodcount = modcount;} }.com.

Private class keyiterator extends hashiterator {public object next () {return next (). getKey ();}}

Private class entryiterator extends hashiterator {public object next () {return next ();}}

Iterator newkeyiterator () {return new keyiterator ();

Iterator newvalueiterator () {return new valueiterator ();}

Iterator newntryiterator () {return new entryiterator ();} private transient set entryset = NULL

Public set keyset () {set ks = keyset; return (ks! = null? ks: (keyset = new keyset));}

private class KeySet extends AbstractSet {public Iterator iterator () {return newKeyIterator ();} public int size () {return size;} public boolean contains (Object o) {return containsKey (o);} public boolean remove (Object o) {Return HashMap.This.RemoventryForKey (o)! = Null;} public void clear () {hashmap.this.clear ();}}

Public Collection Values ​​() {Collection VS = VALUES; RETURN (VS! = NULL? VS: (VALUES = New Values ​​()));}

private class Values ​​extends AbstractCollection {public Iterator iterator () {return newValueIterator ();} public int size () {return size;} public boolean contains (Object o) {return containsValue (o);} public void clear () {HashMap .THIS.CLEAR ();}}

Public set entryset () {set es = entryset; return (es! = null? es: (entryset = new entryset));

private class EntrySet extends AbstractSet {public Iterator iterator () {return newEntryIterator ();} public boolean contains (Object o) {if (! (o instanceof Map.Entry)) return false; Map.Entry e = (Map.Entry) O; entry candidate = getentry (E.GetKey ()); return Candidate! = Null && Candidate.equals (e);} public boolean remove (Object O) {Return RemoveMapping (o)! = null;} public int size ) {Return size;} public void clear () {hashmap.this.clear ();}}

private void writeObject (java.io.ObjectOutputStream s) throws IOException {s.defaultWriteObject (); s.writeInt (table.length); s.writeInt (size); for (Iterator i = entrySet () iterator ();. i .hasNext (); {map.entry E = (map.entry) i.next (); s.writeObject (E.GetKey ()); s.writeObject (E.GetValue ());}} private static final Long serialversionuid = 362498820763181265L;

private void readObject (java.io.ObjectInputStream s) throws IOException, ClassNotFoundException {s.defaultReadObject (); int numBuckets = s.readInt (); table = new Entry [numBuckets]; init (); size = s.readInt () ; for (int i = 0; I

INT Capacity () {Return Table.Length;} Float LoadFactor () {Return LoadFactor;

Collection├List│├LINKEDLIST│├ArrayList│ └Vector│ └Stack └SETMAP├SHASHTABLE ├STMAP└Weakhashmap

The Collection Interface Collection is the most basic set interface, a collection represents a set of object, ie the element of Collection (Elements). Some Collection allows the same elements and others. Some can sort and others can not work. Java SDK does not provide a class directly inherited from Collection, and the classes provided by Java SDK are inherited from the "sub-interface" such as List and SET. All classes for implementing the Collection interface must provide two standard constructor: None parameters for creating an empty collection, a constructor with a Collection parameter is used to create a new Collection, this new Collection and biography Into Collection has the same elements. The latter constructor allows the user to copy a collection. How to traverse each element in Collection? Regardless of the actual type of Collection, it supports a method of Iterator (), which returns an iteration, using this iteration to access each element in the Collection one by one. Typical usage is as follows: Iterator it = Collection.iterator (); // Get an iterative while (it.hasnext ()) {Object Obj = it.next (); // Get the next element} derived by the Collection interface The two interfaces are LIST and SET.

The List interface list is an ordered Collection that can accurately control the insertion of each element using this interface. Users can use an index (the location of the element in LIST, similar to the array subscript) to access the elements in the list, similar to the number of Java. Unlike the SET to be mentioned below, List allows the same elements. In addition to the Iterator () method with the Collection interface, List also provides a listiterator () method, returning a listiterator interface, compared to the standard Iterator interface, the Listiterator is more than some add () methods, allowed to add, Delete, set the element, but also traverse forward or backward. Realize the common class of List interfaces with LinkedList, ArrayList, Vector and Stack. LinkedList class LinkedList implements a List interface, allowing NULL elements. In addition, LinkedList provides additional GET, REMOVE, and INSERT method in the head or tail of LinkedList. These operations allow LinkedList to be used as a stack, queue, or a two-way queue (DEQUE). Note that LinkedList has no synchronization method. If multiple threads accesses a list, you must implement access synchronization yourself. One solution is to construct a synchronized list: list list = collections.synchronizedlist (new linkedlist (...));

ArrayList class ArrayList implements an array of variable sizes. It allows all elements, including NULL. ArrayList is not synchronized. Size, ISEMPTY, GET, and SET methods run time are constants. However, the ADD method is overhead as a constant of the distribution, and the time to add N elements that require o (n). Other method run times is linear. Each ArrayList instance has a capacity, that is, the size of the array for storing the element. This capacity can be automatically increased as new elements continue, but the growth algorithm is not defined. When you need to insert a large number of elements, you can call the EnSureCapacity method before insertion, you can increase the capacity of ArrayList to increase the insertion efficiency. Like LinkedList, ArrayList is also unsynchronized.

VECTOR class Vector is very similar to ArrayList, but the vector is synchronized. Iterator created by Vector, although Iterator created with ArrayList is the same interface, but because the vector is synchronized, when an Iterator is created and is being used, the other thread changes the status of the Vector (for example, add or delete some Element), when you call the method of Iterator, the ConcURRentModificationException will thus be thrown, so the exception must be captured.

The Stack class stack inherits from the vector to implement a stack of a backward first. STACK provides 5 additional methods such that the vector is used as a stack. Basic PUSH and POP methods, as well as the PEEK method to get the elements of the top of the stack, the EMPTY method tests whether the stack is empty, the Search method detects the position of an element in the stack. Stack is just after being created.

Set Interface Set is a collection that does not contain duplicate elements, that is, any two elements E1 and E2 have E1.Equals (E2) = false, and SET has a NULL element. Obviously, the SET constructor has a constraint, and the incoming Collection parameter cannot contain a repeated element. Note: You must be careful to operate the variable object (Mutable Object). If the variable element in a set changed its own state, it will result in object.equals (object) = true. Map interface Please note that MAP does not inherit the Collection interface, and the MAP provides key to value mapping. The same key can not contain the same key, each of which can only map a value. The MAP interface provides three sets of views, and the contents of the MAP can be treated as a set of Key collections, a set of value collections, or a set of Key-Value mappings.

HashTable class hashtable inherits the MAP interface to implement a Hach-Value mapping hash. Any non-null object can be used as a key or value. Add data Using PUT (Key, Value), remove the data using GET (KEY), the time overhead of these two basic operations is constant. HashTable Tuninescence through the INITIAL CAPACITY and LOAD FACTOR. Usually the default Load Factor 0.75 excellent time and space balance. Increasing the Load Factor can save space but the corresponding lookup time will increase, which affects operations like get and PUT. With a simple example of using HashTable, put 1, 2, 3 in Hashtable, their Key is "one", "two", "three": Hashtable number = new hashtable (); NumBers.put ("one" , New Integer (1)); NumBers.Put ("Two", New Integer (2)); NumBers.Put ("Three", New Integer (3)); Take a number, such as 2, with the corresponding Key : Integer n = (Integer) Numbers.get ("Two"); System.out.println ("Two =" N); Since the object as a key will determine the Value corresponding to the hash function Location, therefore any object as a Key must implement a HashCode and Equals method. Hashcode and Equals methods inherit from the root object, if you use a custom class as a key, be quite careful, follow the definition of the hash function, if the two objects are the same, ie obj1.equals (obj2) = true, then Their HashCode must be the same, but if the two objects are different, their hashcode is not necessarily different. If the two different objects of HashCode are the same, this phenomenon is called conflict, and the conflict will result in an increase in the time overhead of the operation hash. So try to define the HashCode () method to speed up the operation of the hash table. If the same object has a different HashCode, the operation of the hash table will have unexpected results (the expected GET method returns null), to avoid this problem, just keep in mind: To copy the equals method and havehcode method, Not only to write one of them. Hashtable is synchronized. HashMap class HashMap and HashTable are similar, and the HashMap is non-synchronous and allows NULL, NULL VALUE, and NULL KEY. However, when HashMap is treated as a Collection (VALUES () method can return to Collection, its iterative subsystem is overhead, and the capacity of HashMap is proportional. Therefore, if the performance of iterative operation is quite important, do not set the initial capacity of HashMap, or Load Factor is too low.

WeakhashMap class WeakhashMap is an improved HashMap that implements "weak references" for Key, if a key is no longer referenced outside, then the key can be recycled by GC.

Summary If it is involved in stacks, queues, etc., consider using List, for quick plug, delete elements, should use LinkedList, if you need to quickly random access, you should use ArrayList. If the program is in a single threaded environment, or the access is only in one thread, considering the non-synchronous class, its efficiency is high, if multiple threads may operate a class at the same time, the synchronous class should be used. Pay special attention to the operation of the hash table, as a key to Key, to properly reply Equals and HashCode methods. Try to return to the interface instead of the actual type, if you returns List instead of arraylist, the client code does not have to change when you need to change ArrayList to linkedList. This is for abstract programming. In Java's depth analysis of HashMap and comparing in the world of Java, regardless of the class, the structure of its structure is the key to the logic and performance of the entire program. Since I have contacted a problem with the performance and logic coexisting, I started researching this problem. Looking for a large and small forum, I also find the "Java Virtual Machine Specification", "Apress, .java.collections. (2001), BM.OCR.6.0.SHARECONNECTOR", and "Thinking in Java" Less than a good answer, so I decompressed the JDK's SRC, expanded to open this article, sharing this article, and confirmed that I have no vulnerabilities. Here, take it to study it.

Hashmap can be described as a large tool for JDK, map each Object, and realize the quick access of the "key-value". But what do you do in reality? Before this, you will introduce the properties of the load factor and capacity. Everyone knows that there is actually a HashMap actual capacity to factor * capacity, its default value is 16 × 0.75 = 12; this is very important, it is very impact on efficiency! When the object stored in HashMap exceeds this capacity, HashMap will restructive access tables. This is a big problem, I will slowly introduce it, anyway, if you already know how many objects you want to store, it is best to be able to accept the actual capacity.

Two key methods, PUT and GET: There is such a concept first, and havehmap is declared Map, Cloneable, Serializable interface, and inheriting the AbstractMap class, which is actually mainly its internal class Hashiterator and several other Iterator classes. Realization, of course, there is a very important inheritance of the Entry internal class of Map.Entry, because everyone has source code, everyone is interested in seeing this part, I mainly want to explain the entry of the entry. It contains four properties of Hash, Value, Key, and Next. The source code of the PUT is as follows

Public Object Put (Object Key, Object Value) {Object K = Masknull (Key);

This is the judgment key value is empty, it is not very profound. In fact, if it is empty, it will return a Static Object as a key value, which is why HashMap allows the empty key value.

INT has = hash (k); int i = indexfor (hash, table.length);

This continuous two steps are the most cattle of Hashmap! I have finished sharing, where Hash is HashCode, which is Object Table, is obtained by indexfor's indexFor. TABLE? ? ? Don't be surprised, in fact, Hashmap is not there, it is put it with table. The most cattle is to return indexes correctly with HASH. The Hash algorithm, I contacted the author Doug of JDK, he suggested that "The Art of Programing Vol3" can hate, I have been looking for it before, I can't find it, he like this, I will More anxious, but unfortunately the pocket is empty! ! ! I don't know if you pay attention to the PUT is actually a return method, which will cover the PUT of the same key value and return to the old value! The following method thoroughly illustrates the structure of HashMap, in fact, a list of entry on the corresponding position: for (entry E = Table [i]; E! = Null; E = E.NEXT) {IF (E.hash == Hash && EQ (k, e.key)) {Object OldValue = E.Value; E.Value = value; // Give the new value to the corresponding key value. E.RecordAccess (this); // null method, the rest of the RETURN OLDVALUE; // returns the corresponding old value of the same key value. }}} Modcount ; // Structural changes Adderry (Hash, K, Value, I); // Add new elements, the key! Return null; / / no key value return}

We take the key method to analyze:

Void Addentry (int 6, int bukeet) {table [bucketindex] = new entry (hash, key, value, table [bucketindex]);

Because Hash's algorithm is likely to have the same HASH code as the different key values, such as: key = "33" and key = Object G are all -8901334, which is the index after IndexFor It's all I, so that this entry's next will point to this original Table [i], and then the next one is the same, and the PUT is looped to obtain the old value. Here, have the structure of Hashmap, everyone knows?

IF (size > = threshold) // This Threshold is the actually accommodated amount resize (2 * Table.Length); // Experience the Object Table Reconstruction

The so-called reconstruction is not God, it is to build a twice large Table (I saw someone in other forums said that it is twice, and I cheated it), and then I then INDEXFOR! note! ! This is efficiency! ! If you can make your havehmap don't need to refactor so many times, the efficiency will be greatly improved! It's almost the same here, Get is much simpler than PUT. Everyone knows PUT, GET is also not much. I think that I am suitable for the whole, it is suitable for unique, if everyone's procedure requires special purposes, it is actually very simple. (The author said to me, he also suggested that I use LinkedHashmap, I have seen the source code, Linkhashmap is actually inheriting Hashmap, then Override's corresponding way, interested, Irself LOOKLOOK, build an Object Table, write The corresponding algorithm is OK. For example, like Vector, List is actually very simple, up to more synchronized statement, in fact, if you want to implement it like a vector, insert, you can use an Object Table, Press index to reject, add, etc. If inserted, delete more, you can build two Object Table, then each element contains the next structure, a table save, if you want to insert i, but I already have an element, connect with next, then Size , and Record its location in another table. Source Analysis: Hashmaphashmap is an implementation used in Java New Collection Framework that instead of HashTable. The difference between HashMap and HashTable is that HashMap is not synchronized and allows NULL values. HashTable inherits Dictionary and uses Enumeration, so it is recommended not to use. HashMap statement as follows: public class HashMap extends AbstractMap implements Map, Cloneable, Serializable about AbstractMap: http: //blog.9cbs.net/treeroot/archive/2004/09/20/110343.aspx about Map: http: // blog .9cbs.net / Treeroot / Archive / 2004/09/20 / 110331.aspx About Cloneable: http://blog.9cbs.net/treeroot/archive/2004/09/07/96936.aspx This class is more complicated, here It is only a few ways to analyze several methods, especially the last few internal classes, but it is more simple. static final int DEFAULT_INITIAL_CAPACITY = 16; initial size default static final int MAXIMUM_CAPACITY = 1 << 30; maximum size initialize static final float DEFAULT_LOAD_FACTOR = 0.75f; default load factor transient Entry [] table; Entry length of one type of array, the array is 2 index.

transient int size; number mapped int threshold; final float loadFactor value at the next expansion; load factor transient volatile int modCount; modified frequency public HashMap (int initialCapacity, float loadFactor) {if (initialCapacity <0) throw new IllegalArgumentException ( "Illegal initial capacity:" initialCapacity); if (initialCapacity> MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; if (loadFactor <= 0 || Float.isNaN (loadFactor)) throw new IllegalArgumentException ( "Illegal load factor:" loadFactor); int Capacity = 1; while (capacity >> 14); h = (h << 4); h ^ = (H >>>

10); RETURN H;} There is no way in HashTable, that is, HashTable is a HashCode value of the object directly, but hashMap has improved this algorithm to get a hash value. Static Boolean EQ (Object X, Object Y) {RETURN X == Y || x.equals (y);} static int indexfor (int h, int length) {Return H & (Length-1);} According to Hash The length of the value and array returns to the location of the HASH value in the array, just a simple relationship. Public int size;} public boolean == 0;} public object get (object key) {Object K = Masknull (key); int 6 = hash (k); int i = IndexFor (hash, Table.Length); entry E = Table [I]; while (true) {if (e == null) Return E; if (E.hash == Hash && EQ (K, E.Key)) Return E.VALUE; E = E.NEXT;} This method is to obtain data, first get a hash value, where the NULL value is covered, and the HASH value is corrected by the function hash (). Then calculate the index value of the hash value in the array. If the reference is referenced to NULL, it indicates that this mapping is not present in HashMap. Otherwise, the whole linked list is all over the list. Here is to return, if you are not found, it is traversed to the end of the chain, and returns NULL. The comparison here is like this: E.hash == Hash && EQ (K, E.Key) That is to say, if the HASH is definitely considered non-equal, EQ is shorted, only in the same situation in Hash, only call Equals. method. Now we should understand that if the two objects Equals returns True, their hashcode should the same truth. If two object calls Equals returns True, but hashcode is different, then they think they are not equal in HashMap. Public Boolean Containskey (Object Key) {Object K = Masknull (Key); Int Hash = Hash (K); INT I = IndexFor (Hash, Table.Length); Entry E = Table [I]; While (E! = null ) {IF (E.hash == Hash && EQ (K, E.key)) Return True; E = E.Next;} Return False;} This method is more simple than the above, first find the hash position, and then traverse the whole Link list, return to TRUE if you find it.

Entry GetEntry (Object Key) {Object K = Masknull (Key); Int Hash = Hash (K); INT I = IndexFor (Hash, Table.Length); Entry E = Table [I]; While (E! = Null && ! (E.hash == Hash && EQ (K, E.KEY))) E = E.Next; Return E;} This method returns an Entry node according to the key value, but also get an index position, traverse the link, if not Find back is NULL. Public Object Put (Object Key, Object Value) {Object K = Masknull (Key); Int Hash = Hash (K); INT I = IndexFor (Hash, Table.Length); for (Entry E = Table [i]; E ! = null; e = E.Next) {if (E.hash == Hash && Eq (K, E.key)) {Object OldValue = E.Value; E.Value = Value; E.RecordAccess (this); Return OldValue;}} modcount ; addentry (hash, k, value, i); return null;} First get the Hash index location, if the reference is reference to null, then insert a mapping, return null. If the reference is not null, you must traverse the chain list. If you find the same key, then update the value, return the original value value. If it is not found in traversal, it means that the Key value does not exist or inserts a mapping. If the Hash value is enough to discrete, that is, if the index is not used, then no traverse is a list. Conversely, if the HASH value is not discrete, the extreme, if it is constant, all mappings will be extremely low on this chain. Here is the simplest example, write two different classes as keys inserted into havehmap, and efficiency will be far different.

Class Good {Int i; public good (int i) {this.i = i;} public boolean equals (object o) {Return (o instanceof good) && (this.i == ((good) O) .i). PUBLIC INT HashCode () {RETURN I;}} Class Bad {INT I; Public Good (INT I) {this.i = i;} public boolean equals (object o) {Return (O InstanceOf Good) && (this. i == (good) o) .i)} public int.com} {return 0;}} Execute code: map m1 = new hashmap (); map m2 = new hashmap (); for (int i = 0; I <100; i ) {m1.put (New Good (i), new integer (i)); // The efficiency here is very high} for (int i = 0; i <100; i ) {m2.put (New Bad (i), new integer (i)); // Almost there is almost two very extreme examples, and if you don't know how much difference is performed. Private Void Putforcreate (Object Key, Object Value) {Object K = Masknull (key); int has = hash (k); int = indexfor (hash, table.Length); for (Entry E = Table [i]; e = NULL; E. E.Hash == Hash && EQ (K, E.Key)) {E.Value = Value; Return;}} CreateEntry (Hash, K, Value, i) } void putallForcreate (MAP M) {for (Iterator i = m.enTryset (). Iterator (); I.hasNext ();) {map.entry E = (map.entry) i.next (); PutforcReate E.GetKey (), E.GETVALUE ());}} The above two methods are called by constructor and clone methods. void resize (int newCapacity) {Entry [] oldTable = table; int oldCapacity = oldTable.length; if (size newCapacity) return; Entry [] newTable = new Entry [newCapacity]; transfer (newTable); Table = newTable; threshold = (int);} This method reassocates space when needed, which is equivalent to ArrayList's EnSureCapacity method, but this is more complicated.

Void Transfer (entry [] src = table; int newcapacity = newTable.Length; for (int J = 0; j = threshold) {n = (int) (N / LoadFactor 1); if (N > Maximum_capacity) n = maximum_capacity; int Capacity = Table.Length; while (capacity

public Object remove (Object key) {Entry e = removeEntryForKey (key); return (e == null e:? e.value);} Entry removeEntryForKey (Object key) {Object k = maskNull (key); int hash = hash (k); int I = indexFor (hash, table.Length); entry prev = table [i]; entry E = prev; while (e! = null) {If e == null means there is no entry next = e. Next; if (E.hash == Hash && EQ (K, E.Key)) {modcount ; size ---; if (prev == e) Table [i] = next; The first element of the list is to delete It is best to add an E.NEXT = NULL. Else prev.next = next; existence is not the first element of the list, here is best to add an E.RecordremovAl (this); Return E Prev = E; E = next;} Return E; here is actually return null;} This method is actually not complicated, and it is also traversal chain table. Here is recommended to add an E.NEXT = NULL, it can be changed to IF (prev == e) Table [i] = next; else prev.next = next; E.NEXT = NULL; this sentence is more, which can improve efficiency. Here is a brief explanation: Because e is the deleted node, delete it is actually pointing to its pointer to its back a node. Therefore, E can be used as an object recovered by GC. You can also have a NEXT pointer points to our data, if e is not recycled. And at this time, the node pointing to E.Next has also become useless, but there is a reference (E.Next), so although the next node of E is useless, but can not be used as a GC recycling object, Unless e-first recovery. Although it is not necessarily a big problem, it will at least affect the recovery efficiency of GC. Just like the foreign key references in the database, it is very troublesome to delete it.

Entry RemoveMapping (Object O) {if (! (O instanceof map.entry) Return null; map.entry entry = (map.entry) O; object k = masknull (entry.getKey ()); int hash = hash K); int I = indexfor (haveh, table.Length); entry prev = Table [i]; entry E = prev; while (e! = null) {entry next = E.NEXT; if (E.hash == Hash && e.equals (entry)) {modcount ; size -; if (prev == e) Table [i] = next; else prev.next = next; E.Recordremoval (this); Return E;} prev = E; E = Next;} Return E;} This method is the same as above.

Public void clear () {modcount ; entry tab [] = table; for (int i = 0; i

Object K2 = E.getKey (); if (k1 == k2 || (k1! = Null && k1.equals (k2))) {Object v1 = getValue (); object v2 = E.GetValue (); if ( V1 == V2 || (v1! = null && v1.equals (v2))) Return True;} return false; (Value == NULL? 0: value.hashcode ());} public string toString () {Return getKey () "=" getValue ();} void recordaccess (havehmap m) {} Void Recordremoval (HashMap M) {}} A static internal class Void Addentry (int Haash, Object Key, Object Value, Int BucketIndex) {Table [BucketIndex] = New Entry (Hash, Key, Value, Table [BucketIndex]); if (Size > = Threshold) Resize (2 * Table.Length);

This can be written better understood: Entry oldHead = table [bucketIndex]; Entry newHead = new Entry (hash, key, value, oldHead); table [bucketIndex] = newHead; void createEntry (int hash, Object key, Object value, int bucketIndex) {table [bucketIndex] = new Entry (hash, key, value, table [bucketIndex]); size ;} private abstract class HashIterator implements Iterator {Entry next; int expectedModCount; int index; Entry current; HashIterator () {expectedModCount = modcount; entry [] t = table; int = null; if (size! = 0) {while (i> 0 && (n = t [- i]) == NULL) ;} next = n; index = i;!} public boolean hasNext () {return next = null;} Entry nextEntry () {if (! modCount = expectedModCount) throw new ConcurrentModificationException (); Entry e = next; if (e == null) throw new nosuchelementException (); entry n = E.Next; entry [] t = table; int = index; while (n == null && i> 0) n = t [- -i]; index = i; next = n; return current = e;} public void remove () {if (current == null) throw new IllegalStateException (); if (! modCount = expectedModCount) throw new ConcurrentModificationException (); Object k = current.key; current = null; HashMap.this.removeEntryForKey (k); expectedModCount = modCount;}} private class ValueIterator extends HashIterator {public Object next () {return nextEntry () value.;

}} Private class KeyIterator extends HashIterator {public Object next () {return nextEntry () getKey ();.}} Private class EntryIterator extends HashIterator {public Object next () {return nextEntry ();}} Iterator newKeyIterator () {return new KeyIterator ();} Iterator newValueIterator () {return new ValueIterator ();} Iterator newEntryIterator () {return new EntryIterator ();} private transient Set entrySet = null; public Set keySet () {Set ks = keySet; return ( ! ks = null ks:? (keySet = new keySet ()));} private class keySet extends AbstractSet {public Iterator iterator () {return newKeyIterator ();} public int size () {return size;} public boolean contains ( Object O) {Return Containskey (O);} public boolean remove (Object O) {return.com Collection Values ​​() {Collection vs = VALUES; RETURN (VS! = NULL? VS: (Value s = new Values ​​()));} private class Values ​​extends AbstractCollection {public Iterator iterator () {return newValueIterator ();} public int size () {return size;} public boolean contains (Object o) {return containsValue (o ); Public void clear () {hashmap.this.clear ();}} public set entryset ()} (es! = Null? Es: (entryset = new entryset);} private class EntrySet extends AbstractSet {public Iterator iterator () {return newEntryIterator ();} public boolean contains (Object o) {if (! (o instanceof Map.Entry)) return false; Map.Entry e = (Map.Entry) o; entry Candidate =

GeTENTRY (E.GetKey ()); return caledate! = null && Candidate.equals (e); public boolean remove (Object O) {Return RemoveMapping (o)! = null;} public int size () {Return Size; } public void clear () {HashMap.this.clear ();}} private void writeObject (java.io.ObjectOutputStream s) throws IOException {s.defaultWriteObject (); s.writeInt (table.length); s.writeInt ( Size); for (Iterator i = entryset (). iterator (); I.hasNext ();) {map.entry E = (map.entry) i.next (); s.writeObject (E.GetKey ()) ; s.writeObject (e.getValue ());}} private static final long serialVersionUID = 362498820763181265L; private void readObject (java.io.ObjectInputStream s) throws IOException, ClassNotFoundException {s.defaultReadObject (); int numBuckets = s.readInt (); Table = new entry [Numbuckets]; init (); size = s.readint (); for (int i = 0; for (int i = 0; i

Static final int default_initial_capacity = 16; Default initialization Size Static Final Int Maximum_capacity = 1 << 30; Maximum Initialization Size

Static final float default_load_factor = 0.75f; default add factor

Transient entry [] Table; an array of entry types, an index of the array length 2.

TRANSIENT INT SIZE; Map of Map

INT THRESHOLD; the value of the next expansion

Final float loadfactor; loading factor

TRANSIENT VOLATILE INT MODMOUNT;

public HashMap (int initialCapacity, float loadFactor) {if (initialCapacity <0) throw new IllegalArgumentException ( "Illegal initial capacity:" initialCapacity); if (initialCapacity> MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; if (loadFactor <= 0 || Float. isNaN (loadFactor)) throw new IllegalArgumentException ( "Illegal load factor:" loadFactor); int capacity = 1; while (capacity

Public HashMap (int initialcapacity) {this (Initialcapacity, default_load_factor);

Public hashmap () {this.loadfactor = default_load_factor; threshold = (int)); Note: This should be a mistake! It should be: threshold = (int) (default_initial_capacity * loadingfactor); table = new entry [default_initial_capacity]; init ();

Public HashMap (MAP M) {this (math.max (math.max (m.size () / default_load_fact 1, default_initial_capacity), default_load_factor); PUTALLFORCREATE (M);}

Void init () {}

Static Final Object Null_Key = New Object ();

Static Object Masknull (Object Key) {return (key == null? null_key: key);

Static Object key) {return (key == null_key? null: key);} static int hash (Object x) {int h = x.hashcode (); h = ~ (h << 9); h ^ = (h >>> 14); h = (h << 4); h ^ = (h >>> 10); return h;} There is no method in HashTable, that is, it is directly used in HashTable. The HashCode value of the object, but hashMap made improved use of this algorithm to get a hash value.

Static Boolean EQ (Object X, Object Y) {Return X == Y || x.equals (y);

Static int indexFor (INT H, INT Length) {RETURN H & (LENGTH-1);} Returns the location of the Hash value in array according to the length of the hash value and array, is just a simple relationship.

Public int size () {return size;}

Public Boolean ISempty () {return size == 0;

Public Object Get {Object K = Masknull (key); int has = hash (k); int I = indexfor (hash, table.Length); entry E = Table [i]; while (true) {i (e == NULL) RETURN E; if (E.hash == Hash && EQ (K, E.Key)) Return E.Value; E = E.NEXT;}} This method is to obtain data, first get Hash value, cover the NULL value, and the HASH value is corrected by the function hash (). Then calculate the index value of the hash value in the array. If the reference is referenced to NULL, it indicates that this mapping is not present in HashMap. Otherwise, the whole linked list is all over the list. Here is to return, if you are not found, it is traversed to the end of the chain, and returns NULL. The comparison here is like this: E.hash == Hash && EQ (K, E.Key) That is to say, if the HASH is definitely considered non-equal, EQ is shorted, only in the same situation in Hash, only call Equals. method. Now we should understand that if the two objects Equals returns True, their hashcode should the same truth. If two object calls Equals returns True, but hashcode is different, then they think they are not equal in HashMap.

Public Boolean Containskey (Object Key) {Object K = Masknull (Key); Int Hash = Hash (K); INT I = IndexFor (Hash, Table.Length); Entry E = Table [I]; While (E! = null ) {IF (E.hash == Hash && EQ (K, E.key)) Return True; E = E.Next;} Return False;} This method is more simple than the above, first find the hash position, and then traverse the whole Link list, return to TRUE if you find it. Entry GetEntry (Object Key) {Object K = Masknull (Key); Int Hash = Hash (K); INT I = IndexFor (Hash, Table.Length); Entry E = Table [I]; While (E! = Null && ! (E.hash == Hash && EQ (K, E.KEY))) E = E.Next; Return E;} This method returns an Entry node according to the key value, but also get an index position, traverse the link, if not Find back is NULL.

Public Object Put (Object Key, Object Value) {Object K = Masknull (Key); Int Hash = Hash (K); INT I = IndexFor (Hash, Table.Length); for (Entry E = Table [i]; E ! = null; e = E.Next) {if (E.hash == Hash && Eq (K, E.key)) {Object OldValue = E.Value; E.Value = Value; E.RecordAccess (this); Return OldValue;}} modcount ; addentry (hash, k, value, i); return null;} First get the Hash index location, if the reference is reference to null, then insert a mapping, return null. If the reference is not null, you must traverse the chain list. If you find the same key, then update the value, return the original value value. If it is not found in traversal, it means that the Key value does not exist or inserts a mapping. If the Hash value is enough to discrete, that is, if the index is not used, then no traverse is a list. Conversely, if the HASH value is not discrete, the extreme, if it is constant, all mappings will be extremely low on this chain. Here is the simplest example, write two different classes as keys inserted into havehmap, and efficiency will be far different. Class Good {Int i; public good (int i) {this.i = i;} public boolean equals (object o) {Return (o instanceof good) && (this.i == ((good) O) .i). PUBLIC INT HashCode () {RETURN I;}} Class Bad {INT I; Public Good (INT I) {this.i = i;} public boolean equals (object o) {Return (O InstanceOf Good) && (this. i == (good) o) .i)} public int.com} {return 0;}} Execute code: map m1 = new hashmap (); map m2 = new hashmap (); for (int i = 0; I <100; i ) {m1.put (New Good (i), new integer (i)); // The efficiency here is very high} for (int i = 0; i <100; i ) {m2.put (New Bad (i), new integer (i)); // Almost there is almost two very extreme examples, and if you don't know how much difference is performed.

Private Void Putforcreate (Object Key, Object Value) {Object K = Masknull (key); int has = hash (k); int = indexfor (hash, table.Length); for (Entry E = Table [i]; e = NULL; E. E.Hash == Hash && EQ (K, E.Key)) {E.Value = Value; Return;}} CreateEntry (Hash, K, Value, i) } void putallForcreate (MAP M) {for (Iterator i = m.enTryset (). Iterator (); I.hasNext ();) {map.entry E = (map.entry) i.next (); PutforcReate E.GetKey (), E.GETVALUE ());}} The above two methods are called by constructor and clone methods.

void resize (int newCapacity) {Entry [] oldTable = table; int oldCapacity = oldTable.length; if (size newCapacity) return; Entry [] newTable = new Entry [newCapacity]; transfer (newTable); Table = newTable; threshold = (int);} This method reassocates space when needed, which is equivalent to ArrayList's EnSureCapacity method, but this is more complicated.

Void Transfer (entry [] src = table; int newcapacity = newTable.Length; for (int J = 0; j

Public void Putall (MAP T) {INT N = T.Size (); if (n == 0) Return; if (n> = threshold) {n = (int) (N / LoadFactor 1); if (N > Maximum_capacity) n = maximum_capacity; int Capacity = Table.Length; while (capacity

Entry RemoventryForKey (Object Key) {Object K = Masknull (key); int has = hash (k); int = indexfor (hash, table.Length); entry prev = table [i]; entry E = prev; while e! = null) {If e == null means there is no entry next = E.Next; if (E.hash == Hash && EQ (K, E.Key)) {modcount ; size--; if (prev = = E) Table [i] = next; the first element of the list is to delete, here is best to add an E.NEXT = NULL. Else prev.next = next; existence is not the first element of the list, here It is best to add E.Next = null. E.Recordremoval (this); return e;} prev = E; E = next;} return e; here is actually return null;} This method is not complicated, and the traversal table Here, it is recommended to add an E.Next = NULL, which can be changed to if (prev == e) table [i] = next; else prev.next = next; E.NEXT = NULL; this sentence is more, it can improve efficiency . Here is a brief explanation: Because e is the deleted node, delete it is actually pointing to its pointer to its back a node. Therefore, E can be used as an object recovered by GC. You can also have a NEXT pointer points to our data, if e is not recycled. And at this time, the node pointing to E.Next has also become useless, but there is a reference (E.Next), so although the next node of E is useless, but can not be used as a GC recycling object, Unless e-first recovery. Although it is not necessarily a big problem, it will at least affect the recovery efficiency of GC. Just like the foreign key references in the database, it is very troublesome to delete it.

Entry RemoveMapping (Object O) {if (! (O instanceof map.entry) Return null; map.entry entry = (map.entry) O; object k = masknull (entry.getKey ()); int hash = hash K); int I = indexfor (haveh, table.Length); entry prev = Table [i]; entry E = prev; while (e! = null) {entry next = E.NEXT; if (E.hash == Hash && e.equals (entry)) {modcount ; size -; if (prev == e) Table [i] = next; else prev.next = next; E.Recordremoval (this); Return E;} prev = E; E = Next;} Return E;} This method is the same as above. Public void clear () {modcount ; entry tab [] = table; for (int i = 0; i

Public Boolean ContaSvalue ({if (value == null) Return ContainSnullValue (); entry tab [] = table; for (int i = 0; i

Private Boolean ContainSnullValue () {entry Tab [] = Table; for (int i = 0; i

public Object clone () {HashMap result = null; try {result = (HashMap) super.clone ();} catch (CloneNotSupportedException e) {// assert false;} result.table = new Entry [table.length]; result .entrySet = null; result.modCount = 0; result.size = 0; result.init (); result.putAllForCreate (this); return result;} static class Entry implements Map.Entry {final Object key; Object value; final INTHESH; Entry Next; Entry (int h, object k, object v, entry n) {value = v; next = n; key = k; hash = h;} public object getKey () {Return unmasknull (key); } public Object getValue () {return value;} public Object setValue (Object newValue) {Object oldValue = value; value = newValue; return oldValue;!} public boolean equals (Object o) {if ((o instanceof Map.Entry) Return False; map.entry E = (map.entry) O; Object K1 = getKey (); Object K2 = E.GetKey (); if (k1 == k2 || (k1! = Nu LL && K1.Equals (k2))) {Object v1 = getValue (); object v2 = E.GETVALUE (); if (v1 == V2 || (v1! = null && v1.equals (v2))) Return True;} returnaf ()} public int 6code () {return (key == null_key? 0: key.hashcode ()) ^ (value == null? 0: value.hashcode ());} public string toString () {Return getKey () "=" getValue ();} void recordaccess (HashMap M) {} void recordremoval (havehmap m) {}} A static internal class

void addEntry (int hash, Object key, Object value, int bucketIndex) {table [bucketIndex] = new Entry (hash, key, value, table [bucketIndex]); if (size > = threshold) resize (2 * table.length ); Note this method, insert the head of the same table. This can be written better understood: Entry oldHead = table [bucketIndex]; Entry newHead = new Entry (hash, key, value, oldHead); table [bucketIndex] = newHead; void createEntry (int hash, Object key, Object value, int BucketIndex) {Table [BucketIndex] = New Entry (Hash, Key, Value, Table [BucketIndex]); SIZE ;}

private abstract class HashIterator implements Iterator {Entry next; int expectedModCount; int index; Entry current; HashIterator () {expectedModCount = modCount; Entry [] t = table; int i = t.length; Entry n = null; if (size! = 0) {While (n = t [n =]) == null);} next = n; index = i;} public boolean Hasnext () {Return next! = Null;} entry nextentry () {if (! modCount = expectedModCount) throw new ConcurrentModificationException (); Entry e = next; if (e == null) throw new NoSuchElementException (); Entry n = e.next; Entry [] t = table; int i = index; while (n == NULL && I> 0) n = t [- i]; index = i; next = n; return current = e;} public void remove () {if (current == null) Throw new IllegalStateException (); if (MODCOUNT! = Expectedmodcount) throw new concurrentmodificationException (); Object K = Current.Key; Cu Rrent = null; hashmap.this.removeentryforKey (k); expectedmodcount = modcount;} }.com.

Private class keyiterator extends hashiterator {public object next () {return next (). getKey ();}}

Private class entryiterator extends hashiterator {public object next () {return next ();}}

Iterator newkeyiterator () {return new keyiterator ();

Iterator newvalueiterator () {return new valueiterator ();}

Iterator newntryiterator () {return new entryiterator ();} private transient set entryset = NULL

Public set keyset () {set ks = keyset; return (ks! = null? ks: (keyset = new keyset));}

private class KeySet extends AbstractSet {public Iterator iterator () {return newKeyIterator ();} public int size () {return size;} public boolean contains (Object o) {return containsKey (o);} public boolean remove (Object o) {Return HashMap.This.RemoventryForKey (o)! = Null;} public void clear () {hashmap.this.clear ();}}

Public Collection Values ​​() {Collection VS = VALUES; RETURN (VS! = NULL? VS: (VALUES = New Values ​​()));}

private class Values ​​extends AbstractCollection {public Iterator iterator () {return newValueIterator ();} public int size () {return size;} public boolean contains (Object o) {return containsValue (o);} public void clear () {HashMap .THIS.CLEAR ();}}

Public set entryset () {set es = entryset; return (es! = null? es: (entryset = new entryset));

private class EntrySet extends AbstractSet {public Iterator iterator () {return newEntryIterator ();} public boolean contains (Object o) {if (! (o instanceof Map.Entry)) return false; Map.Entry e = (Map.Entry) O; entry candidate = getentry (E.GetKey ()); return Candidate! = Null && Candidate.equals (e);} public boolean remove (Object O) {Return RemoveMapping (o)! = null;} public int size ) {Return size;} public void clear () {hashmap.this.clear ();}}

private void writeObject (java.io.ObjectOutputStream s) throws IOException {s.defaultWriteObject (); s.writeInt (table.length); s.writeInt (size); for (Iterator i = entrySet () iterator ();. i .hasNext (); {map.entry E = (map.entry) i.next (); s.writeObject (E.GetKey ()); s.writeObject (E.GetValue ());}} private static final Long serialversionuid = 362498820763181265L;

private void readObject (java.io.ObjectInputStream s) throws IOException, ClassNotFoundException {s.defaultReadObject (); int numBuckets = s.readInt (); table = new Entry [numBuckets]; init (); size = s.readInt () ; for (int i = 0; I

INT Capacity () {Return Table.Length;} Float LoadFactor () {Return LoadFactor;

Hashmap can be described as a large tool for JDK, map each Object, and realize the quick access of the "key-value". But what do you do in reality? Before this, you will introduce the properties of the load factor and capacity. Everyone knows that there is actually a HashMap actual capacity to factor * capacity, its default value is 16 × 0.75 = 12; this is very important, it is very impact on efficiency! When the object stored in HashMap exceeds this capacity, HashMap will restructive access tables. This is a big problem, I will slowly introduce it, anyway, if you already know how many objects you want to store, it is best to be able to accept the actual capacity.

Two key methods, PUT and GET: There is such a concept first, and havehmap is declared Map, Cloneable, Serializable interface, and inheriting the AbstractMap class, which is actually mainly its internal class Hashiterator and several other Iterator classes. Realization, of course, there is a very important inheritance of the Entry internal class of Map.Entry, because everyone has source code, everyone is interested in seeing this part, I mainly want to explain the entry of the entry. It contains four properties of Hash, Value, Key, and Next. The source code of the PUT is as follows

Public Object Put (Object Key, Object Value) {Object K = Masknull (Key);

This is the judgment key value is empty, it is not very profound. In fact, if it is empty, it will return a Static Object as a key value, which is why HashMap allows the empty key value. INT has = hash (k); int i = indexfor (hash, table.length);

This continuous two steps are the most cattle of Hashmap! I have finished sharing, where Hash is HashCode, which is Object Table, is obtained by indexfor's indexFor. TABLE? ? ? Don't be surprised, in fact, Hashmap is not there, it is put it with table. The most cattle is to return indexes correctly with HASH. The Hash algorithm, I contacted the author Doug of JDK, he suggested that "The Art of Programing Vol3" can hate, I have been looking for it before, I can't find it, he like this, I will More anxious, but unfortunately the pocket is empty! ! ! I don't know if you pay attention to the PUT is actually a return method, which will cover the PUT of the same key value and return to the old value! The following method thoroughly illustrates the structure of HashMap, in fact, a list of entry in the corresponding position:

For (Entry E = Table [I]; E! = NULL; E = E.Next) {IF (E.hash == Hash && EQ (K, E.Key) {Object OldValue = E.Value; E. Value = value; // Give the new value to the corresponding key value. E.RecordAccess (this); // null method, the rest of the RETURN OLDVALUE; // returns the corresponding old value of the same key value. }}} Modcount ; // Structural changes Adderry (Hash, K, Value, I); // Add new elements, the key! Return null; / / no key value return}

We take the key method to analyze:

Void Addentry (int 6, int bukeet) {table [bucketindex] = new entry (hash, key, value, table [bucketindex]);

Because Hash's algorithm is likely to have the same HASH code as the different key values, such as: key = "33" and key = Object G are all -8901334, which is the index after IndexFor It's all I, so that this entry's next will point to this original Table [i], and then the next one is the same, and the PUT is looped to obtain the old value. Here, have the structure of Hashmap, everyone knows?

IF (size > = threshold) // This Threshold is the actually accommodated amount resize (2 * Table.Length); // Experience the Object Table Reconstruction

The so-called reconstruction is not God, it is to build a twice large Table (I saw someone in other forums said that it is twice, and I cheated it), and then I then INDEXFOR! note! ! This is efficiency! ! If you can make your havehmap don't need to refactor so many times, the efficiency will be greatly improved! It's almost the same here, Get is much simpler than PUT. Everyone knows PUT, GET is also not much. I think that I am suitable for the whole, it is suitable for unique, if everyone's procedure requires special purposes, it is actually very simple. (The author said to me, he also suggested that I use LinkedHashmap, I have seen the source code, Linkhashmap is actually inheriting Hashmap, then Override's corresponding way, interested, Irself LOOKLOOK, build an Object Table, write The corresponding algorithm is OK. For example, like Vector, List is actually very simple, up to more synchronized statement, in fact, if you want to implement it like a vector, insert, you can use an Object Table, Press index to reject, add, etc. If inserted, delete more, you can build two Object Table, then each element contains the next structure, a table save, if you want to insert i, but I already have an element, connect with next, then Size , and Record its location in another table. Source Analysis: Hashmaphashmap is an implementation used in Java New Collection Framework that instead of HashTable. The difference between HashMap and HashTable is that HashMap is not synchronized and allows NULL values. HashTable inherits Dictionary and uses Enumeration, so it is recommended not to use. HashMap statement as follows: public class HashMap extends AbstractMap implements Map, Cloneable, Serializable about AbstractMap: http: //blog.9cbs.net/treeroot/archive/2004/09/20/110343.aspx about Map: http: // blog .9cbs.net / Treeroot / Archive / 2004/09/20 / 110331.aspx About Cloneable: http://blog.9cbs.net/treeroot/archive/2004/09/07/96936.aspx This class is more complicated, here It is only a few ways to analyze several methods, especially the last few internal classes, but it is more simple. static final int DEFAULT_INITIAL_CAPACITY = 16; initial size default static final int MAXIMUM_CAPACITY = 1 << 30; maximum size initialize static final float DEFAULT_LOAD_FACTOR = 0.75f; default load factor transient Entry [] table; Entry length of one type of array, the array is 2 index.

transient int size; number mapped int threshold; final float loadFactor value at the next expansion; load factor transient volatile int modCount; modified frequency public HashMap (int initialCapacity, float loadFactor) {if (initialCapacity <0) throw new IllegalArgumentException ( "Illegal initial capacity:" initialCapacity); if (initialCapacity> MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; if (loadFactor <= 0 || Float.isNaN (loadFactor)) throw new IllegalArgumentException ( "Illegal load factor:" loadFactor); int Capacity = 1; while (capacity >> 14); h = (h << 4); h ^ = (H >>>

10); RETURN H;} There is no way in HashTable, that is, HashTable is a HashCode value of the object directly, but hashMap has improved this algorithm to get a hash value. Static Boolean EQ (Object X, Object Y) {RETURN X == Y || x.equals (y);} static int indexfor (int h, int length) {Return H & (Length-1);} According to Hash The length of the value and array returns to the location of the HASH value in the array, just a simple relationship. Public int size;} public boolean == 0;} public object get (object key) {Object K = Masknull (key); int 6 = hash (k); int i = IndexFor (hash, Table.Length); entry E = Table [I]; while (true) {if (e == null) Return E; if (E.hash == Hash && EQ (K, E.Key)) Return E.VALUE; E = E.NEXT;} This method is to obtain data, first get a hash value, where the NULL value is covered, and the HASH value is corrected by the function hash (). Then calculate the index value of the hash value in the array. If the reference is referenced to NULL, it indicates that this mapping is not present in HashMap. Otherwise, the whole linked list is all over the list. Here is to return, if you are not found, it is traversed to the end of the chain, and returns NULL. The comparison here is like this: E.hash == Hash && EQ (K, E.Key) That is to say, if the HASH is definitely considered non-equal, EQ is shorted, only in the same situation in Hash, only call Equals. method. Now we should understand that if the two objects Equals returns True, their hashcode should the same truth. If two object calls Equals returns True, but hashcode is different, then they think they are not equal in HashMap. Public Boolean Containskey (Object Key) {Object K = Masknull (Key); Int Hash = Hash (K); INT I = IndexFor (Hash, Table.Length); Entry E = Table [I]; While (E! = null ) {IF (E.hash == Hash && EQ (K, E.key)) Return True; E = E.Next;} Return False;} This method is more simple than the above, first find the hash position, and then traverse the whole Link list, return to TRUE if you find it.

Entry GetEntry (Object Key) {Object K = Masknull (Key); Int Hash = Hash (K); INT I = IndexFor (Hash, Table.Length); Entry E = Table [I]; While (E! = Null && ! (E.hash == Hash && EQ (K, E.KEY))) E = E.Next; Return E;} This method returns an Entry node according to the key value, but also get an index position, traverse the link, if not Find back is NULL. Public Object Put (Object Key, Object Value) {Object K = Masknull (Key); Int Hash = Hash (K); INT I = IndexFor (Hash, Table.Length); for (Entry E = Table [i]; E ! = null; e = E.Next) {if (E.hash == Hash && Eq (K, E.key)) {Object OldValue = E.Value; E.Value = Value; E.RecordAccess (this); Return OldValue;}} modcount ; addentry (hash, k, value, i); return null;} First get the Hash index location, if the reference is reference to null, then insert a mapping, return null. If the reference is not null, you must traverse the chain list. If you find the same key, then update the value, return the original value value. If it is not found in traversal, it means that the Key value does not exist or inserts a mapping. If the Hash value is enough to discrete, that is, if the index is not used, then no traverse is a list. Conversely, if the HASH value is not discrete, the extreme, if it is constant, all mappings will be extremely low on this chain. Here is the simplest example, write two different classes as keys inserted into havehmap, and efficiency will be far different.

Class Good {Int i; public good (int i) {this.i = i;} public boolean equals (object o) {Return (o instanceof good) && (this.i == ((good) O) .i). PUBLIC INT HashCode () {RETURN I;}} Class Bad {INT I; Public Good (INT I) {this.i = i;} public boolean equals (object o) {Return (O InstanceOf Good) && (this. i == (good) o) .i)} public int.com} {return 0;}} Execute code: map m1 = new hashmap (); map m2 = new hashmap (); for (int i = 0; I <100; i ) {m1.put (New Good (i), new integer (i)); // The efficiency here is very high} for (int i = 0; i <100; i ) {m2.put (New Bad (i), new integer (i)); // Almost there is almost two very extreme examples, and if you don't know how much difference is performed. Private Void Putforcreate (Object Key, Object Value) {Object K = Masknull (key); int has = hash (k); int = indexfor (hash, table.Length); for (Entry E = Table [i]; e = NULL; E. E.Hash == Hash && EQ (K, E.Key)) {E.Value = Value; Return;}} CreateEntry (Hash, K, Value, i) } void putallForcreate (MAP M) {for (Iterator i = m.enTryset (). Iterator (); I.hasNext ();) {map.entry E = (map.entry) i.next (); PutforcReate E.GetKey (), E.GETVALUE ());}} The above two methods are called by constructor and clone methods. void resize (int newCapacity) {Entry [] oldTable = table; int oldCapacity = oldTable.length; if (size newCapacity) return; Entry [] newTable = new Entry [newCapacity]; transfer (newTable); Table = newTable; threshold = (int);} This method reassocates space when needed, which is equivalent to ArrayList's EnSureCapacity method, but this is more complicated.

Void Transfer (entry [] src = table; int newcapacity = newTable.Length; for (int J = 0; j = threshold) {n = (int) (N / LoadFactor 1); if (N > Maximum_capacity) n = maximum_capacity; int Capacity = Table.Length; while (capacity

public Object remove (Object key) {Entry e = removeEntryForKey (key); return (e == null e:? e.value);} Entry removeEntryForKey (Object key) {Object k = maskNull (key); int hash = hash (k); int I = indexFor (hash, table.Length); entry prev = table [i]; entry E = prev; while (e! = null) {If e == null means there is no entry next = e. Next; if (E.hash == Hash && EQ (K, E.Key)) {modcount ; size ---; if (prev == e) Table [i] = next; The first element of the list is to delete It is best to add an E.NEXT = NULL. Else prev.next = next; existence is not the first element of the list, here is best to add an E.RecordremovAl (this); Return E Prev = E; E = next;} Return E; here is actually return null;} This method is actually not complicated, and it is also traversal chain table. Here is recommended to add an E.NEXT = NULL, it can be changed to IF (prev == e) Table [i] = next; else prev.next = next; E.NEXT = NULL; this sentence is more, which can improve efficiency. Here is a brief explanation: Because e is the deleted node, delete it is actually pointing to its pointer to its back a node. Therefore, E can be used as an object recovered by GC. You can also have a NEXT pointer points to our data, if e is not recycled. And at this time, the node pointing to E.Next has also become useless, but there is a reference (E.Next), so although the next node of E is useless, but can not be used as a GC recycling object, Unless e-first recovery. Although it is not necessarily a big problem, it will at least affect the recovery efficiency of GC. Just like the foreign key references in the database, it is very troublesome to delete it.

Entry RemoveMapping (Object O) {if (! (O instanceof map.entry) Return null; map.entry entry = (map.entry) O; object k = masknull (entry.getKey ()); int hash = hash K); int I = indexfor (haveh, table.Length); entry prev = Table [i]; entry E = prev; while (e! = null) {entry next = E.NEXT; if (E.hash == Hash && e.equals (entry)) {modcount ; size -; if (prev == e) Table [i] = next; else prev.next = next; E.Recordremoval (this); Return E;} prev = E; E = Next;} Return E;} This method is the same as above.

Public void clear () {modcount ; entry tab [] = table; for (int i = 0; i

Object K2 = E.getKey (); if (k1 == k2 || (k1! = Null && k1.equals (k2))) {Object v1 = getValue (); object v2 = E.GetValue (); if ( V1 == V2 || (v1! = null && v1.equals (v2))) Return True;} return false; (Value == NULL? 0: value.hashcode ());} public string toString () {Return getKey () "=" getValue ();} void recordaccess (havehmap m) {} Void Recordremoval (HashMap M) {}} A static internal class Void Addentry (int Haash, Object Key, Object Value, Int BucketIndex) {Table [BucketIndex] = New Entry (Hash, Key, Value, Table [BucketIndex]); if (Size > = Threshold) Resize (2 * Table.Length);

This can be written better understood: Entry oldHead = table [bucketIndex]; Entry newHead = new Entry (hash, key, value, oldHead); table [bucketIndex] = newHead; void createEntry (int hash, Object key, Object value, int bucketIndex) {table [bucketIndex] = new Entry (hash, key, value, table [bucketIndex]); size ;} private abstract class HashIterator implements Iterator {Entry next; int expectedModCount; int index; Entry current; HashIterator () {expectedModCount = modcount; entry [] t = table; int = null; if (size! = 0) {while (i> 0 && (n = t [- i]) == NULL) ;} next = n; index = i;!} public boolean hasNext () {return next = null;} Entry nextEntry () {if (! modCount = expectedModCount) throw new ConcurrentModificationException (); Entry e = next; if (e == null) throw new nosuchelementException (); entry n = E.Next; entry [] t = table; int = index; while (n == null && i> 0) n = t [- -i]; index = i; next = n; return current = e;} public void remove () {if (current == null) throw new IllegalStateException (); if (! modCount = expectedModCount) throw new ConcurrentModificationException (); Object k = current.key; current = null; HashMap.this.removeEntryForKey (k); expectedModCount = modCount;}} private class ValueIterator extends HashIterator {public Object next () {return nextEntry () value.;

}} Private class KeyIterator extends HashIterator {public Object next () {return nextEntry () getKey ();.}} Private class EntryIterator extends HashIterator {public Object next () {return nextEntry ();}} Iterator newKeyIterator () {return new KeyIterator ();} Iterator newValueIterator () {return new ValueIterator ();} Iterator newEntryIterator () {return new EntryIterator ();} private transient Set entrySet = null; public Set keySet () {Set ks = keySet; return ( ! ks = null ks:? (keySet = new keySet ()));} private class keySet extends AbstractSet {public Iterator iterator () {return newKeyIterator ();} public int size () {return size;} public boolean contains ( Object O) {Return Containskey (O);} public boolean remove (Object O) {return.com Collection Values ​​() {Collection vs = VALUES; RETURN (VS! = NULL? VS: (Value s = new Values ​​()));} private class Values ​​extends AbstractCollection {public Iterator iterator () {return newValueIterator ();} public int size () {return size;} public boolean contains (Object o) {return containsValue (o ); Public void clear () {hashmap.this.clear ();}} public set entryset ()} (es! = Null? Es: (entryset = new entryset);} private class EntrySet extends AbstractSet {public Iterator iterator () {return newEntryIterator ();} public boolean contains (Object o) {if (! (o instanceof Map.Entry)) return false; Map.Entry e = (Map.Entry) o; entry Candidate =

GeTENTRY (E.GetKey ()); return caledate! = null && Candidate.equals (e); public boolean remove (Object O) {Return RemoveMapping (o)! = null;} public int size () {Return Size; } public void clear () {HashMap.this.clear ();}} private void writeObject (java.io.ObjectOutputStream s) throws IOException {s.defaultWriteObject (); s.writeInt (table.length); s.writeInt ( Size); for (Iterator i = entryset (). iterator (); I.hasNext ();) {map.entry E = (map.entry) i.next (); s.writeObject (E.GetKey ()) ; s.writeObject (e.getValue ());}} private static final long serialVersionUID = 362498820763181265L; private void readObject (java.io.ObjectInputStream s) throws IOException, ClassNotFoundException {s.defaultReadObject (); int numBuckets = s.readInt (); Table = new entry [Numbuckets]; init (); size = s.readint (); for (int i = 0; for (int i = 0; i

Static final int default_initial_capacity = 16; Default initialization Size Static Final Int Maximum_capacity = 1 << 30; Maximum Initialization Size

Static final float default_load_factor = 0.75f; default add factor

Transient entry [] Table; an array of entry types, an index of the array length 2.

TRANSIENT INT SIZE; Map of Map

INT THRESHOLD; the value of the next expansion

Final float loadfactor; loading factor

TRANSIENT VOLATILE INT MODMOUNT;

public HashMap (int initialCapacity, float loadFactor) {if (initialCapacity <0) throw new IllegalArgumentException ( "Illegal initial capacity:" initialCapacity); if (initialCapacity> MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; if (loadFactor <= 0 || Float. isNaN (loadFactor)) throw new IllegalArgumentException ( "Illegal load factor:" loadFactor); int capacity = 1; while (capacity

Public HashMap (int initialcapacity) {this (Initialcapacity, default_load_factor);

Public hashmap () {this.loadfactor = default_load_factor; threshold = (int)); Note: This should be a mistake! It should be: threshold = (int) (default_initial_capacity * loadingfactor); table = new entry [default_initial_capacity]; init ();

Public HashMap (MAP M) {this (math.max (math.max (m.size () / default_load_fact 1, default_initial_capacity), default_load_factor); PUTALLFORCREATE (M);}

Void init () {}

Static Final Object Null_Key = New Object ();

Static Object Masknull (Object Key) {return (key == null? null_key: key);

Static Object key) {return (key == null_key? null: key);} static int hash (Object x) {int h = x.hashcode (); h = ~ (h << 9); h ^ = (h >>> 14); h = (h << 4); h ^ = (h >>> 10); return h;} There is no method in HashTable, that is, it is directly used in HashTable. The HashCode value of the object, but hashMap made improved use of this algorithm to get a hash value.

Static Boolean EQ (Object X, Object Y) {Return X == Y || x.equals (y);

Static int indexFor (INT H, INT Length) {RETURN H & (LENGTH-1);} Returns the location of the Hash value in array according to the length of the hash value and array, is just a simple relationship.

Public int size () {return size;}

Public Boolean ISempty () {return size == 0;

Public Object Get {Object K = Masknull (key); int has = hash (k); int I = indexfor (hash, table.Length); entry E = Table [i]; while (true) {i (e == NULL) RETURN E; if (E.hash == Hash && EQ (K, E.Key)) Return E.Value; E = E.NEXT;}} This method is to obtain data, first get Hash value, cover the NULL value, and the HASH value is corrected by the function hash (). Then calculate the index value of the hash value in the array. If the reference is referenced to NULL, it indicates that this mapping is not present in HashMap. Otherwise, the whole linked list is all over the list. Here is to return, if you are not found, it is traversed to the end of the chain, and returns NULL. The comparison here is like this: E.hash == Hash && EQ (K, E.Key) That is to say, if the HASH is definitely considered non-equal, EQ is shorted, only in the same situation in Hash, only call Equals. method. Now we should understand that if the two objects Equals returns True, their hashcode should the same truth. If two object calls Equals returns True, but hashcode is different, then they think they are not equal in HashMap.

Public Boolean Containskey (Object Key) {Object K = Masknull (Key); Int Hash = Hash (K); INT I = IndexFor (Hash, Table.Length); Entry E = Table [I]; While (E! = null ) {IF (E.hash == Hash && EQ (K, E.key)) Return True; E = E.Next;} Return False;} This method is more simple than the above, first find the hash position, and then traverse the whole Link list, return to TRUE if you find it. Entry GetEntry (Object Key) {Object K = Masknull (Key); Int Hash = Hash (K); INT I = IndexFor (Hash, Table.Length); Entry E = Table [I]; While (E! = Null && ! (E.hash == Hash && EQ (K, E.KEY))) E = E.Next; Return E;} This method returns an Entry node according to the key value, but also get an index position, traverse the link, if not Find back is NULL.

Public Object Put (Object Key, Object Value) {Object K = Masknull (Key); Int Hash = Hash (K); INT I = IndexFor (Hash, Table.Length); for (Entry E = Table [i]; E ! = null; e = E.Next) {if (E.hash == Hash && Eq (K, E.key)) {Object OldValue = E.Value; E.Value = Value; E.RecordAccess (this); Return OldValue;}} modcount ; addentry (hash, k, value, i); return null;} First get the Hash index location, if the reference is reference to null, then insert a mapping, return null. If the reference is not null, you must traverse the chain list. If you find the same key, then update the value, return the original value value. If it is not found in traversal, it means that the Key value does not exist or inserts a mapping. If the Hash value is enough to discrete, that is, if the index is not used, then no traverse is a list. Conversely, if the HASH value is not discrete, the extreme, if it is constant, all mappings will be extremely low on this chain. Here is the simplest example, write two different classes as keys inserted into havehmap, and efficiency will be far different. Class Good {Int i; public good (int i) {this.i = i;} public boolean equals (object o) {Return (o instanceof good) && (this.i == ((good) O) .i). PUBLIC INT HashCode () {RETURN I;}} Class Bad {INT I; Public Good (INT I) {this.i = i;} public boolean equals (object o) {Return (O InstanceOf Good) && (this. i == (good) o) .i)} public int.com} {return 0;}} Execute code: map m1 = new hashmap (); map m2 = new hashmap (); for (int i = 0; I <100; i ) {m1.put (New Good (i), new integer (i)); // The efficiency here is very high} for (int i = 0; i <100; i ) {m2.put (New Bad (i), new integer (i)); // Almost there is almost two very extreme examples, and if you don't know how much difference is performed.

Private Void Putforcreate (Object Key, Object Value) {Object K = Masknull (key); int has = hash (k); int = indexfor (hash, table.Length); for (Entry E = Table [i]; e = NULL; E. E.Hash == Hash && EQ (K, E.Key)) {E.Value = Value; Return;}} CreateEntry (Hash, K, Value, i) } void putallForcreate (MAP M) {for (Iterator i = m.enTryset (). Iterator (); I.hasNext ();) {map.entry E = (map.entry) i.next (); PutforcReate E.GetKey (), E.GETVALUE ());}} The above two methods are called by constructor and clone methods.

void resize (int newCapacity) {Entry [] oldTable = table; int oldCapacity = oldTable.length; if (size newCapacity) return; Entry [] newTable = new Entry [newCapacity]; transfer (newTable); Table = newTable; threshold = (int);} This method reassocates space when needed, which is equivalent to ArrayList's EnSureCapacity method, but this is more complicated.

Void Transfer (entry [] src = table; int newcapacity = newTable.Length; for (int J = 0; j

Public void Putall (MAP T) {INT N = T.Size (); if (n == 0) Return; if (n> = threshold) {n = (int) (N / LoadFactor 1); if (N > Maximum_capacity) n = maximum_capacity; int Capacity = Table.Length; while (capacity

Entry RemoventryForKey (Object Key) {Object K = Masknull (key); int has = hash (k); int = indexfor (hash, table.Length); entry prev = table [i]; entry E = prev; while e! = null) {If e == null means there is no entry next = E.Next; if (E.hash == Hash && EQ (K, E.Key)) {modcount ; size--; if (prev = = E) Table [i] = next; the first element of the list is to delete, here is best to add an E.NEXT = NULL. Else prev.next = next; existence is not the first element of the list, here It is best to add E.Next = null. E.Recordremoval (this); return e;} prev = E; E = next;} return e; here is actually return null;} This method is not complicated, and the traversal table Here, it is recommended to add an E.Next = NULL, which can be changed to if (prev == e) table [i] = next; else prev.next = next; E.NEXT = NULL; this sentence is more, it can improve efficiency . Here is a brief explanation: Because e is the deleted node, delete it is actually pointing to its pointer to its back a node. Therefore, E can be used as an object recovered by GC. You can also have a NEXT pointer points to our data, if e is not recycled. And at this time, the node pointing to E.Next has also become useless, but there is a reference (E.Next), so although the next node of E is useless, but can not be used as a GC recycling object, Unless e-first recovery. Although it is not necessarily a big problem, it will at least affect the recovery efficiency of GC. Just like the foreign key references in the database, it is very troublesome to delete it.

Entry RemoveMapping (Object O) {if (! (O instanceof map.entry) Return null; map.entry entry = (map.entry) O; object k = masknull (entry.getKey ()); int hash = hash K); int I = indexfor (haveh, table.Length); entry prev = Table [i]; entry E = prev; while (e! = null) {entry next = E.NEXT; if (E.hash == Hash && e.equals (entry)) {modcount ; size -; if (prev == e) Table [i] = next; else prev.next = next; E.Recordremoval (this); Return E;} prev = E; E = Next;} Return E;} This method is the same as above. Public void clear () {modcount ; entry tab [] = table; for (int i = 0; i

Public Boolean ContaSvalue ({if (value == null) Return ContainSnullValue (); entry tab [] = table; for (int i = 0; i

Private Boolean ContainSnullValue () {entry Tab [] = Table; for (int i = 0; i

public Object clone () {HashMap result = null; try {result = (HashMap) super.clone ();} catch (CloneNotSupportedException e) {// assert false;} result.table = new Entry [table.length]; result .entrySet = null; result.modCount = 0; result.size = 0; result.init (); result.putAllForCreate (this); return result;} static class Entry implements Map.Entry {final Object key; Object value; final INTHESH; Entry Next; Entry (int h, object k, object v, entry n) {value = v; next = n; key = k; hash = h;} public object getKey () {Return unmasknull (key); } public Object getValue () {return value;} public Object setValue (Object newValue) {Object oldValue = value; value = newValue; return oldValue;!} public boolean equals (Object o) {if ((o instanceof Map.Entry) Return False; map.entry E = (map.entry) O; Object K1 = getKey (); Object K2 = E.GetKey (); if (k1 == k2 || (k1! = Nu LL && K1.Equals (k2))) {Object v1 = getValue (); object v2 = E.GETVALUE (); if (v1 == V2 || (v1! = null && v1.equals (v2))) Return True;} returnaf ()} public int 6code () {return (key == null_key? 0: key.hashcode ()) ^ (value == null? 0: value.hashcode ());} public string toString () {Return getKey () "=" getValue ();} void recordaccess (HashMap M) {} void recordremoval (havehmap m) {}} A static internal class

void addEntry (int hash, Object key, Object value, int bucketIndex) {table [bucketIndex] = new Entry (hash, key, value, table [bucketIndex]); if (size > = threshold) resize (2 * table.length ); Note this method, insert the head of the same table. This can be written better understood: Entry oldHead = table [bucketIndex]; Entry newHead = new Entry (hash, key, value, oldHead); table [bucketIndex] = newHead; void createEntry (int hash, Object key, Object value, int BucketIndex) {Table [BucketIndex] = New Entry (Hash, Key, Value, Table [BucketIndex]); SIZE ;}

private abstract class HashIterator implements Iterator {Entry next; int expectedModCount; int index; Entry current; HashIterator () {expectedModCount = modCount; Entry [] t = table; int i = t.length; Entry n = null; if (size! = 0) {While (n = t [n =]) == null);} next = n; index = i;} public boolean Hasnext () {Return next! = Null;} entry nextentry () {if (! modCount = expectedModCount) throw new ConcurrentModificationException (); Entry e = next; if (e == null) throw new NoSuchElementException (); Entry n = e.next; Entry [] t = table; int i = index; while (n == NULL && I> 0) n = t [- i]; index = i; next = n; return current = e;} public void remove () {if (current == null) Throw new IllegalStateException (); if (MODCOUNT! = Expectedmodcount) throw new concurrentmodificationException (); Object K = Current.Key; Cu Rrent = null; hashmap.this.removeentryforKey (k); expectedmodcount = modcount;} }.com.

Private class keyiterator extends hashiterator {public object next () {return next (). getKey ();}}

Private class entryiterator extends hashiterator {public object next () {return next ();}}

Iterator newkeyiterator () {return new keyiterator ();

Iterator newvalueiterator () {return new valueiterator ();}

Iterator newntryiterator () {return new entryiterator ();} private transient set entryset = NULL

Public set keyset () {set ks = keyset; return (ks! = null? ks: (keyset = new keyset));}

private class KeySet extends AbstractSet {public Iterator iterator () {return newKeyIterator ();} public int size () {return size;} public boolean contains (Object o) {return containsKey (o);} public boolean remove (Object o) {Return HashMap.This.RemoventryForKey (o)! = Null;} public void clear () {hashmap.this.clear ();}}

Public Collection Values ​​() {Collection VS = VALUES; RETURN (VS! = NULL? VS: (VALUES = New Values ​​()));}

private class Values ​​extends AbstractCollection {public Iterator iterator () {return newValueIterator ();} public int size () {return size;} public boolean contains (Object o) {return containsValue (o);} public void clear () {HashMap .THIS.CLEAR ();}}

Public set entryset () {set es = entryset; return (es! = null? es: (entryset = new entryset));

private class EntrySet extends AbstractSet {public Iterator iterator () {return newEntryIterator ();} public boolean contains (Object o) {if (! (o instanceof Map.Entry)) return false; Map.Entry e = (Map.Entry) O; entry candidate = getentry (E.GetKey ()); return Candidate! = Null && Candidate.equals (e);} public boolean remove (Object O) {Return RemoveMapping (o)! = null;} public int size ) {Return size;} public void clear () {hashmap.this.clear ();}}

private void writeObject (java.io.ObjectOutputStream s) throws IOException {s.defaultWriteObject (); s.writeInt (table.length); s.writeInt (size); for (Iterator i = entrySet () iterator ();. i .hasNext (); {map.entry E = (map.entry) i.next (); s.writeObject (E.GetKey ()); s.writeObject (E.GetValue ());}} private static final Long serialversionuid = 362498820763181265L;

private void readObject (java.io.ObjectInputStream s) throws IOException, ClassNotFoundException {s.defaultReadObject (); int numBuckets = s.readInt (); table = new Entry [numBuckets]; init (); size = s.readInt () ; for (int i = 0; I

INT Capacity () {Return Table.Length;} Float LoadFactor () {Return LoadFactor;

转载请注明原文地址:https://www.9cbs.com/read-49995.html

New Post(0)