首先,我个人对Hash算法不熟悉,参考了这位大神的博客:
http://www.cnblogs.com/dolphin0520/archive/2012/09/28/2700000.html
粗略的理解是,Hash算法在分块的时候,如果分的过多会导致查找元素效率低。并做了以下的实验:
1 /* 2 * Copyright 2001-2004 The Apache Software Foundation. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 /* 17 * $Id: Hashtable.java,v 1.2.4.1 2005/09/06 11:05:18 pvedula Exp $ 18 */ 19 20 import java.awt.List; 21 import java.util.ArrayList; 22 import java.util.Collection; 23 import java.util.Collections; 24 import java.util.Comparator; 25 import java.util.Enumeration; 26 import java.util.HashMap; 27 import java.util.HashSet; 28 import java.util.TreeMap; 29 30 /** 31 * IMPORTANT NOTE: 32 * This code was taken from Sun's Java1.1 JDK java.util.HashTable.java 33 * All "synchronized" keywords and some methods we do not need have been 34 * all been removed. 35 */ 36 37 /** 38 * Object that wraps entries in the hash-table 39 * 40 * @author Morten Jorgensen 41 */ 42 class HashtableEntry { 43 int hash; 44 Object key; 45 Object value; 46 HashtableEntry next; 47 48 protected Object clone() { 49 HashtableEntry entry = new HashtableEntry(); 50 entry.hash = hash; 51 entry.key = key; 52 entry.value = value; 53 entry.next = (next != null) ? (HashtableEntry) next.clone() : null; 54 return entry; 55 } 56 } 57 58 /** 59 * The main hash-table implementation 60 */ 61 public class MyHashTable { 62 63 private transient HashtableEntry table[]; // hash-table entries 64 private transient int count; // number of entries 65 private int threshold; // current size of hash-tabke 66 private float loadFactor; // load factor 67 68 private HashMap<Integer, Integer> indexcount = new HashMap<Integer, Integer>(); 69 70 /** 71 * Constructs a new, empty hashtable with the specified initial capacity and 72 * the specified load factor. 73 */ 74 public MyHashTable(int initialCapacity, float loadFactor) { 75 if (initialCapacity <= 0) 76 initialCapacity = 11; 77 if (loadFactor <= 0.0) 78 loadFactor = 0.75f; 79 this.loadFactor = loadFactor; 80 table = new HashtableEntry[initialCapacity]; 81 threshold = (int) (initialCapacity * loadFactor); 82 } 83 84 /** 85 * Constructs a new, empty hashtable with the specified initial capacity and 86 * default load factor. 87 */ 88 public MyHashTable(int initialCapacity) { 89 this(initialCapacity, 0.75f); 90 } 91 92 /** 93 * Constructs a new, empty hashtable with a default capacity and load 94 * factor. 95 */ 96 public MyHashTable() { 97 this(101, 0.75f); 98 } 99 100 /** 101 * Returns the number of keys in this hashtable. 102 */ 103 public int size() { 104 return count; 105 } 106 107 /** 108 * Tests if this hashtable maps no keys to values. 109 */ 110 public boolean isEmpty() { 111 return count == 0; 112 } 113 114 /** 115 * Returns an enumeration of the keys in this hashtable. 116 */ 117 public Enumeration keys() { 118 return new HashtableEnumerator(table, true); 119 } 120 121 /** 122 * Returns an enumeration of the values in this hashtable. Use the 123 * Enumeration methods on the returned object to fetch the elements 124 * sequentially. 125 */ 126 public Enumeration elements() { 127 return new HashtableEnumerator(table, false); 128 } 129 130 /** 131 * Tests if some key maps into the specified value in this hashtable. This 132 * operation is more expensive than the <code>containsKey</code> method. 133 */ 134 public boolean contains(Object value) { 135 136 if (value == null) 137 throw new NullPointerException(); 138 139 int i; 140 HashtableEntry e; 141 HashtableEntry tab[] = table; 142 143 for (i = tab.length; i-- > 0;) { 144 for (e = tab[i]; e != null; e = e.next) { 145 if (e.value.equals(value)) { 146 return true; 147 } 148 } 149 } 150 return false; 151 } 152 153 /** 154 * Tests if the specified object is a key in this hashtable. 155 */ 156 public boolean containsKey(Object key) { 157 HashtableEntry e; 158 HashtableEntry tab[] = table; 159 int hash = key.hashCode(); 160 int index = (hash & 0x7FFFFFFF) % tab.length; 161 162 for (e = tab[index]; e != null; e = e.next) 163 if ((e.hash == hash) && e.key.equals(key)) 164 return true; 165 166 return false; 167 } 168 169 /** 170 * Returns the value to which the specified key is mapped in this hashtable. 171 */ 172 public Object get(Object key) { 173 HashtableEntry e; 174 HashtableEntry tab[] = table; 175 int hash = key.hashCode(); 176 int index = (hash & 0x7FFFFFFF) % tab.length; 177 178 for (e = tab[index]; e != null; e = e.next) 179 if ((e.hash == hash) && e.key.equals(key)) 180 return e.value; 181 182 return null; 183 } 184 185 /** 186 * Rehashes the contents of the hashtable into a hashtable with a larger 187 * capacity. This method is called automatically when the number of keys in 188 * the hashtable exceeds this hashtable's capacity and load factor. 189 */ 190 protected void rehash() { 191 HashtableEntry e, old; 192 int i, index; 193 int oldCapacity = table.length; 194 HashtableEntry oldTable[] = table; 195 196 int newCapacity = oldCapacity * 2 + 1; 197 HashtableEntry newTable[] = new HashtableEntry[newCapacity]; 198 199 threshold = (int) (newCapacity * loadFactor); 200 table = newTable; 201 202 for (i = oldCapacity; i-- > 0;) { 203 for (old = oldTable[i]; old != null;) { 204 e = old; 205 old = old.next; 206 index = (e.hash & 0x7FFFFFFF) % newCapacity; 207 e.next = newTable[index]; 208 newTable[index] = e; 209 } 210 } 211 } 212 213 /** 214 * Maps the specified <code>key</code> to the specified <code>value</code> 215 * in this hashtable. Neither the key nor the value can be <code>null</code> 216 * . 217 * <p> 218 * The value can be retrieved by calling the <code>get</code> method with a 219 * key that is equal to the original key. 220 */ 221 public Object put(Object key, Object value) { 222 // Make sure the value is not null 223 if (value == null) 224 throw new NullPointerException(); 225 226 // Makes sure the key is not already in the hashtable. 227 HashtableEntry e; 228 HashtableEntry tab[] = table; 229 int hash = key.hashCode(); 230 int index = (hash & 0x7FFFFFFF) % tab.length; 231 if (indexcount.get(Integer.valueOf(index)) != null) { 232 indexcount.put(Integer.valueOf(index), 233 indexcount.get(Integer.valueOf(index)) + 1); 234 } else { 235 indexcount.put(Integer.valueOf(index), 1); 236 } 237 238 for (e = tab[index]; e != null; e = e.next) { 239 if ((e.hash == hash) && e.key.equals(key)) { 240 Object old = e.value; 241 e.value = value; 242 return old; 243 } 244 } 245 246 // Rehash the table if the threshold is exceeded 247 if (count >= threshold) { 248 rehash(); 249 return put(key, value); 250 } 251 252 // Creates the new entry. 253 e = new HashtableEntry(); 254 e.hash = hash; 255 e.key = key; 256 e.value = value; 257 e.next = tab[index]; 258 tab[index] = e; 259 count++; 260 return null; 261 } 262 263 public void printIndexCount() { 264 Collection<Integer> values = indexcount.values(); 265 ArrayList<Integer> arrays = new ArrayList<Integer>(values); 266 Collections.sort(arrays,new Comparator<Integer>() { 267 268 @Override 269 public int compare(Integer o1, Integer o2) { 270 return o2.compareTo(o1); 271 } 272 }); 273 HashMap<Integer, Integer> hMap = new HashMap<Integer, Integer>(); 274 for (Integer integer : arrays) { 275 if(hMap.containsKey(integer)){ 276 hMap.put(integer, hMap.get(integer)+1); 277 }else{ 278 hMap.put(integer, 1); 279 } 280 } 281 System.out.println(hMap); 282 } 283 284 /** 285 * Removes the key (and its corresponding value) from this hashtable. This 286 * method does nothing if the key is not in the hashtable. 287 */ 288 public Object remove(Object key) { 289 HashtableEntry e, prev; 290 HashtableEntry tab[] = table; 291 int hash = key.hashCode(); 292 int index = (hash & 0x7FFFFFFF) % tab.length; 293 for (e = tab[index], prev = null; e != null; prev = e, e = e.next) { 294 if ((e.hash == hash) && e.key.equals(key)) { 295 if (prev != null) 296 prev.next = e.next; 297 else 298 tab[index] = e.next; 299 count--; 300 return e.value; 301 } 302 } 303 return null; 304 } 305 306 /** 307 * Clears this hashtable so that it contains no keys. 308 */ 309 public void clear() { 310 HashtableEntry tab[] = table; 311 for (int index = tab.length; --index >= 0;) 312 tab[index] = null; 313 count = 0; 314 } 315 316 /** 317 * Returns a rather long string representation of this hashtable. Handy for 318 * debugging - leave it here!!! 319 */ 320 public String toString() { 321 int i; 322 int max = size() - 1; 323 StringBuffer buf = new StringBuffer(); 324 Enumeration k = keys(); 325 Enumeration e = elements(); 326 buf.append("{"); 327 328 for (i = 0; i <= max; i++) { 329 String s1 = k.nextElement().toString(); 330 String s2 = e.nextElement().toString(); 331 buf.append(s1 + "=" + s2); 332 if (i < max) 333 buf.append(", "); 334 } 335 buf.append("}"); 336 return buf.toString(); 337 } 338 339 /** 340 * A hashtable enumerator class. This class should remain opaque to the 341 * client. It will use the Enumeration interface. 342 */ 343 class HashtableEnumerator implements Enumeration { 344 boolean keys; 345 int index; 346 HashtableEntry table[]; 347 HashtableEntry entry; 348 349 HashtableEnumerator(HashtableEntry table[], boolean keys) { 350 this.table = table; 351 this.keys = keys; 352 this.index = table.length; 353 } 354 355 public boolean hasMoreElements() { 356 if (entry != null) { 357 return true; 358 } 359 while (index-- > 0) { 360 if ((entry = table[index]) != null) { 361 return true; 362 } 363 } 364 return false; 365 } 366 367 public Object nextElement() { 368 if (entry == null) { 369 while ((index-- > 0) && ((entry = table[index]) == null)) 370 ; 371 } 372 if (entry != null) { 373 HashtableEntry e = entry; 374 entry = e.next; 375 return keys ? e.key : e.value; 376 } 377 return null; 378 } 379 } 380 381 }
1 public class TestHash { 2 3 public static void main(String[] args) { 4 int length = 10000 * 20; 5 MyHashTable map = new MyHashTable(); 6 for (int i = 0; i < length; i++) { 7 map.put(new Person(i + "", i + ""), i + ""); 8 } 9 map.printIndexCount(); 10 } 11 }
1 /** 2 * 具有相同身份证信息的人就是同一个人 3 * 4 * @author Lucifer 5 * 6 */ 7 public class Person { 8 9 private String name; 10 private String identityCard; 11 private long age; 12 13 public Person(String name, String identityCard) { 14 this.name = name; 15 this.setIdentityCard(identityCard); 16 } 17 18 public String getName() { 19 return name; 20 } 21 22 public void setName(String name) { 23 this.name = name; 24 } 25 26 public String getIdentityCard() { 27 return identityCard; 28 } 29 30 public void setIdentityCard(String identityCard) { 31 this.identityCard = identityCard; 32 } 33 34 @Override 35 public int hashCode() { 36 return this.name.hashCode(); 37 } 38 @Override 39 public boolean equals(Object obj) { 40 if (this == obj) 41 return true; 42 if (obj == null) 43 return false; 44 if (getClass() != obj.getClass()) 45 return false; 46 Person other = (Person) obj; 47 if (age != other.age) 48 return false; 49 if (identityCard == null) { 50 if (other.identityCard != null) 51 return false; 52 } else if (!identityCard.equals(other.identityCard)) 53 return false; 54 if (name == null) { 55 if (other.name != null) 56 return false; 57 } else if (!name.equals(other.name)) 58 return false; 59 return true; 60 } 61 62 public long getAge() { 63 return age; 64 } 65 66 public void setAge(long age) { 67 this.age = age; 68 } 69 }
结果是,如果Person类重写了hashCode方法,hashtable的分块会更加细致。这样查找的效率就提高了。
我的理解有限,如果哪位大神看到了,请指点一二,非常感谢。