1. Introduction
1 /** 2 * Description:Create a new class as the key of the map 3 */ 4 public class Groundhog 5 { 6 protected int number; 7 8 public Groundhog(){ 9 } 10 public Groundhog(int number) 11 { 12 this.number = number; 13 } 14 15 @Override 16 public String toString() 17 { 18 return "Groundhog{" + "number=" + number + '}'; 19 } 20 } 21 22 /** 23 * Description:Create a new class as the value of the map 24 */ 25 public class Prediction 26 { 27 private boolean shadow=Math.random() > 0.5; 28 29 @Override 30 public String toString() 31 { 32 if (shadow) return "Six more weeks of Winter"; 33 else return "Early Spring!"; 34 } 35 } 36 37 /** 38 * Description:Test Class 39 */ 40 public class SpringDetector 41 { 42 public static void detectSpring(Class grondHotClass) throws Exception{ 43 Constructor constructor = grondHotClass.getConstructor(new Class[]{int.class}); 44 Map map=new HashMap(); 45 for (int i=0;i<10;i++){ 46 map.put(constructor.newInstance(new Object[]{new Integer(i)}),new Prediction()); 47 } 48 System.out.println("map="+map); 49 50 Groundhog groundhog=(Groundhog)constructor.newInstance(new Object[]{new Integer(3)}); 51 System.out.println(groundhog); 52 53 if (map.containsKey(groundhog)) {//Find out if this key exists 54 System.out.println((Prediction)map.get(groundhog)); 55 }else { 56 System.out.println("key not find:"+groundhog); 57 } 58 59 } 60 public static void main(String[] args) 61 { 62 try { 63 detectSpring(Groundhog.class); 64 } catch (Exception e) { 65 e.printStackTrace(); 66 } 67 } 68 }
Looking at this result, the question arises. Groudhog{number=3} is clearly present in the map. Why does the result show Key not found?Where is the problem?The Groudhog class did not override the hashCode() method, so here the hashCode() method of Object is used to generate the hash code, whereas he calculates the hash code using the object's address by default.Therefore, the hash code for the first instance generated by Groudhog(3) is different from that generated by Groudhog(3), so the key cannot be found.However, simply rewriting hashCode() is not enough unless you override the equals () method.The reason is that different objects may calculate the same hashCode value. The hashCode value is not unique. When the hashCode value is the same, equals() is used to determine if the current "key" is "the same" as the key that exists in the table, that is, "
2. Understanding hashCode()
The value of hashing is speed: hashing allows queries to execute quickly.Since the bottleneck of speed is the query of keys, and the data structure that stores the fastest set of elements is an array, it represents the information of keys. Note that arrays do not hold the keys themselves.A number is generated from the Key object as the index of the array's subscript.This number is a hash code generated (or becomes a hash function) by the hashCode() defined in Object.At the same time, to solve the problem of fixed array capacity, different keys can produce the same subscript.So for arrays?How can I save multiple values in the same subscript index?The original array did not save the Value directly, but instead saved the List of Values.Then use equals() to query the values in the list linearly.This part of the query is naturally slower, but if there are good hash functions, each subscript index holds only a small number of values and compares only a few elements, it will be much faster.
I don't know if you understand what I'm saying above.But that's okay. Here's an example to help you understand.But I've been confused by the question: Why do a hashCode subscript have multiple values?Since there can only be a unique key in hashMap, there can only be a unique value in that subscript.Here's a new concept, hash conflict, borrowing an example from the Web:
For example, the length of the array is 5.At this point, one data is 6.So how do you store this 6 in an array that's only 5 in length?According to the modulus method, 6%5 is calculated and the result is 1, then 6 is placed in the position of array subscript 1.So, 7 should be at 2.At this point, hash conflicts have not yet occurred.At this time, there is a data of 11, according to the modulus method, 11%5 = 1, also equal to 1.So where the original array subscript is 1, there is already a number, which is 6.Then the position of 1 is calculated, and then the position of array 1 must store two numbers.This is called a hash conflict.Conflicts are then stored in order.So the solution used in Java here is to save a List on this hashCode, and when you encounter the same hashCode, add elements to it.That's the essence of hash's principle!Ha-ha, tangle with me for a day.
3. Performance Factors of HashMap
Capacity: The number in the hash list.
Initial capacity: The number of buckets when creating a hash list.Both HashMap and HashSet allow you to set the initialization capacity in the constructor.
Size: The number of records in the current hash list.
Load factor: equal to "size/capacity".The load factor is 0, representing an empty hash list, 0.5 representing a half-full hash list, and so on.Light-loaded hashes are characterized by fewer conflicts, suitable insertions, and suitable queries (but iterator traversal is slower).The constructors of HashMap and hashSet allow you to formulate load factors.This means that when the load reaches the set value, the container automatically multiplies its capacity and reallocates the existing objects into a new container (this is called "rehashing").The default load factor for HashMap is 0.75, which is a good trade-off between time and space.
Note: To balance the hash distribution, Java hash functions use an integer power of 2 as the ideal capacity for a hash list.Dividing and remainder are the slowest operations for modern processors.Use a hash of the integer power of 2 to replace division with a mask.Because get() is the most used operation, the% operation to find the remainder is the majority of its overhead, which can be eliminated by using an integer power of 2 (which may also have some impact on hashCode())
4. How to rewrite hashCode()
Now IDE tools can automatically help us rewrite hashCode() and equals() methods, but that may not be optimal. There are two principles for rewriting hashCode():
- It must be fast and meaningful.That is, it must generate a hash code based on the contents of the object.
- A well-distributed hash code should be generated.If the hash codes are all clustered together, the load can become heavy in some areas.
Here's how to write a basic guide for a decent hashCode():
1. Give the int variable result a non-zero value constant, such as 17.
2. Calculate an int hash code c for each meaningful attribute f (that is, each attribute that can be equals() within each object:
3. Consolidated hash value: result=37*result+c;
4. Return to result;
5. Check the results generated by hashCode() to ensure that the same object has the same hash code.
5. Customize HashMap
Here we will write a hashMap to help you understand the underlying principles. If you understand the code below, you will also understand the principles of hashCode.
/** * Description:First create a new class as an object stored in the map and override the hashCode() and equals() methods */ public class MPair implements Map.Entry,Comparable { private Object key,value; public MPair(Object key,Object value) { this.key = key; this.value=value; } @Override public int compareTo(Object o) { return ((Comparable)key).compareTo(((MPair)o).key); } @Override public Object getKey() { return key; } @Override public Object getValue() { return value; } @Override public int hashCode() { int result = key != null ? key.hashCode() : 0; result = 31 * result + (value != null ? value.hashCode() : 0); return result; } @Override public boolean equals(Object o) { return key.equals(((MPair)o).key); } @Override public Object setValue(Object v) { Object result=value; this.value=v; return result; } @Override public String toString() { return "MPair{" + "key=" + key + ", value=" + value + '}'; }
public class SimpleHashMap extends AbstractMap { private static final int SZ=3;//Set an initial size hash table capacity private LinkedList[] linkedLists=new LinkedList[SZ];//Build one hash Array, using linkedList Realization public Object put(Object key,Object value){ Object result=null; int index=key.hashCode() % SZ;//Yes key The value of index if (index<0) index=-index; if (linkedLists[index]==null) linkedLists[index]=new LinkedList();//If this index Location has no object, create a new one LinkedList linkedList = linkedLists[index];//Take this out index Object linkedList MPair mPair = new MPair(key,value);//New Object to Store mPair ListIterator listIterator = linkedList.listIterator(); boolean found =false; while (listIterator.hasNext()){//Traverse through this index Located List,If you find the same object as before(according to equals To compare),Then update that key Corresponding value Object next = listIterator.next(); if (next.equals(mPair)){ result = ((MPair) next).getValue(); listIterator.set(mPair);//Update Action found=true; break; } } if (!found) linkedLists[index].add(mPair);//If this object is not found, then here index Of List Add a new element to the object. return result; } public Object get(Object key){ int index = key.hashCode() % SZ; if (index<0) index=-index; if (linkedLists[index]==null) return null; LinkedList linkedList = linkedLists[index]; MPair mPair=new MPair(key,null);//Create a new empty object value because equals()The comparison depends on their key Is it equal, while List When traversing objects in the key To find the object. ListIterator listIterator = linkedList.listIterator(); while (listIterator.hasNext()){ Object next = listIterator.next(); if (next.equals(mPair)) return ((MPair)next).getValue();//Found this key Just return to this value } return null; } @Override public Set<Entry> entrySet() { Set set=new HashSet(); for (int i=0;i<linkedLists.length;i++){ if (linkedLists[i]==null) continue; Iterator iterator = linkedLists[i].iterator(); while (iterator.hasNext()){ set.add(iterator.next()); } } return set; } public static void main(String[] args) { SimpleHashMap simpleHashMap=new SimpleHashMap(); simpleHashMap.put("1", "1"); simpleHashMap.put("2", "2"); simpleHashMap.put("3","3"); simpleHashMap.put("4","4");//There are four elements, of which key 1 and 1 key Is 4 index It's the same, so index 1 List There are two elements on it. System.out.println(simpleHashMap); Object o = simpleHashMap.get("1"); System.out.println(o); Object o1 = simpleHashMap.get("4"); System.out.println(o1); } }
6. Conclusion
Don't know if you understand it?After a whole day, I finally got a general idea of the principles.The writing is rough. Let's take a look. After all, the writer who can't cook is not a good programmer.Ha-ha... Or, maybe I have a lot of places that I don't understand well, please don't hesitate to teach!
Original work, reproduced from: http://www.cnblogs.com/jmcui/p/7419779.html