点击上方蓝字 中科软之java项目开发综合知识
本公众号主要推送javaweb开发相关技术,基础知识点,同时会深入剖析复杂的问题,分享一些优秀的框架,大型项目经验,当今最流行的Javaweb技术,热点科技新闻,招聘信息等等。点击上方的蓝字,这样您每天可以看到更多的java知识和资讯!完全是免费订阅,请放心关注。
原文连接:http://wely.iteye.com/blog/2334552
HashMap中有一些我们容易忽视的点
1. 关于key的hash和equals
Java代码
1. public V put(K key, V value) {
2. if (table == EMPTY_TABLE) {
3. inflateTable(threshold);
4. }
5. if (key == null)
6. return putForNullKey(value);
7. int hash = hash(key);
8. int i = indexFor(hash, table.length);
9. for (Entry<K,V> e = table[i]; e != null; e = e.next) {
10. Object k;
11. if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
12. V oldValue = e.value;
13. e.value = value;
14. e.recordAccess(this);
15. return oldValue;
16. }
17. }
18.
19. modCount++;
20. addEntry(hash, key, value, i);
21. return null;
22. }
由上述代码知道,hash值是用来确定bucketIndex,equals是用来和链表上的值比较,因此对于key是自定义的类,强烈建议重写hashCode和equals方法。此处也是容易引起内存泄露的点。
下面摘抄一段JDK里面的注释,
Java代码
1. /**
2. * Returns a hash code value for the object. This method is
3. * supported for the benefit of hash tables such as those provided by
4. * {@link java.util.HashMap}.
5. * <p>
6. * The general contract of {@code hashCode} is:
7. * <ul>
8. * <li>Whenever it is invoked on the same object more than once during
9. * an execution of a Java application, the {@code hashCode} method
10. * must consistently return the same integer, provided no information
11. * used in {@code equals} comparisons on the object is modified.
12. * This integer need not remain consistent from one execution of an
13. * application to another execution of the same application.
14. * <li>If two objects are equal according to the {@code equals(Object)}
15. * method, then calling the {@code hashCode} method on each of
16. * the two objects must produce the same integer result.
17. * <li>It is <em>not</em> required that if two objects are unequal
18. * according to the {@link java.lang.Object#equals(java.lang.Object)}
19. * method, then calling the {@code hashCode} method on each of the
20. * two objects must produce distinct integer results. However, the
21. * programmer should be aware that producing distinct integer results
22. * for unequal objects may improve the performance of hash tables.
23. * </ul>
24. * <p>
25. * As much as is reasonably practical, the hashCode method defined by
26. * class {@code Object} does return distinct integers for distinct
27. * objects. (This is typically implemented by converting the internal
28. * address of the object into an integer, but this implementation
29. * technique is not required by the
30. * Java<font size="-2"><sup>TM</sup></font> programming language.)
31. *
32. * @return a hash code value for this object.
33. * @see java.lang.Object#equals(java.lang.Object)
34. * @see java.lang.System#identityHashCode
35. */
36. public native int hashCode();
2. rehash的条件
Java代码
1. void addEntry(int hash, K key, V value, int bucketIndex) {
2. if ((size >= threshold) && (null != table[bucketIndex])) {
3. resize(2 * table.length);
4. hash = (null != key) ? hash(key) : 0;
5. bucketIndex = indexFor(hash, table.length);
6. }
7.
8. createEntry(hash, key, value, bucketIndex);
9. }
if条件告诉我们rehash的条件要同时满足两个:map中元素个数不小于阀值即容量*负载因子,对应的bucketIndex处有元素。
另外,如下代码作备忘,
Java代码
1. static int indexFor(int h, int length) {
2. // assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2";
3. return h & (length-1);
4. }
3. 可以插入(null, null)吗
Java代码
1. Map<String, String> map = new HashMap<String, String>();
2. map.put(null, null);
3. System.out.println(map.size()); // 1
4.
5. private V putForNullKey(V value) {
6. for (Entry<K,V> e = table[0]; e != null; e = e.next) {
7. if (e.key == null) {
8. V oldValue = e.value;
9. e.value = value;
10. e.recordAccess(this);
11. return oldValue;
12. }
13. }
14. modCount++;
15. addEntry(0, null, value, 0); // hash = 0, bucketIndex = 0
16. return null;
17. }
注意,Hashtable和ConcurrentHashMap进行put时若value为null,将抛出NullPointerException。
4. table默认初始大小 - 16
Java代码
1. public HashMap(int initialCapacity, float loadFactor) {
2. // ...
3.
4. this.loadFactor = loadFactor; // 0.75
5. threshold = initialCapacity; // 16
6. init(); // nothing
7. }
8.
9. public V put(K key, V value) {
10. if (table == EMPTY_TABLE) {
11. inflateTable(threshold);
12. }
13. // ...
14.}
15.
16.private void inflateTable(int toSize) {
17. // Find a power of 2 >= toSize
18. int capacity = roundUpToPowerOf2(toSize); // 16
19.
20. threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);
21. table = new Entry[capacity];
22. initHashSeedAsNeeded(capacity);
23. }
24.
25.private static int roundUpToPowerOf2(int number) {
26. // assert number >= 0 : "number must be non-negative";
27. return number >= MAXIMUM_CAPACITY
28. ? MAXIMUM_CAPACITY
29. : (number > 1) ? Integer.highestOneBit((number - 1) << 1) : 1;
30. }
5. 关于HashMap里的hash(Object key)方法
Java代码
1. final int hash(Object k) {
2. int h = hashSeed;
3. if (0 != h && k instanceof String) {
4. return sun.misc.Hashing.stringHash32((String) k);
5. }
6.
7. h ^= k.hashCode();
8.
9. // This function ensures that hashCodes that differ only by
10. // constant multiples at each bit position have a bounded
11. // number of collisions (approximately 8 at default load factor).
12. h ^= (h >>> 20) ^ (h >>> 12);
13. return h ^ (h >>> 7) ^ (h >>> 4);
14. }
15.
16./**
17. * Initialize the hashing mask value. We defer initialization until we
18. * really need it.
19. */
20. final boolean initHashSeedAsNeeded(int capacity) {
21. boolean currentAltHashing = hashSeed != 0;
22. boolean useAltHashing = sun.misc.VM.isBooted() &&
23. (capacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);
24. boolean switching = currentAltHashing ^ useAltHashing;
25. if (switching) {
26. hashSeed = useAltHashing
27. ? sun.misc.Hashing.randomHashSeed(this)
28. : 0;
29. }
30. return switching;
31. }
有人用微信聊天,有人却在微信中学习,成长。下面是2016最HOT公众号,赶快试试新的关注方法吧!
关注方式
★长按二维码,选择“识别图中二维码”进行关注。