激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

香港云服务器
服務器之家 - 編程語言 - JAVA教程 - java中HashMap的原理分析

java中HashMap的原理分析

2020-04-11 12:26hebedich JAVA教程

HashMap在Java開發中有著非常重要的角色地位,每一個Java程序員都應該了解HashMap。詳細地闡述HashMap中的幾個概念,并深入探討HashMap的內部結構和實現細節,討論HashMap的性能問題

我們先來看這樣的一道面試題:

在 HashMap 中存放的一系列鍵值對,其中鍵為某個我們自定義的類型。放入 HashMap 后,我們在外部把某一個 key 的屬性進行更改,然后我們再用這個 key 從 HashMap 里取出元素,這時候 HashMap 會返回什么?

文中已給出示例代碼與答案,但關于HashMap的原理沒有做出解釋。

1. 特性

我們可以用任何類作為HashMap的key,但是對于這些類應該有什么限制條件呢?且看下面的代碼:

?
1
2
3
4
5
6
7
8
9
10
11
public class Person {
  private String name;
 
  public Person(String name) {
    this.name = name;
  }
}
 
Map<Person, String> testMap = new HashMap<>();
testMap.put(new Person("hello"), "world");
testMap.get(new Person("hello")); // ---> null

本是想取出具有相等字段值Person類的value,結果卻是null。對HashMap稍有了解的人看出來——Person類并沒有override hashcode方法,導致其繼承的是Object的hashcode(返回是其內存地址)。這也是為什么常用不變類如String(或Integer等)做為HashMap的key的原因。那么,HashMap是如何利用hashcode給key做快速索引的呢?

2. 原理

首先,我們來看《Thinking in Java》中一個簡單HashMap的實現方案:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
//: containers/SimpleHashMap.java
// A demonstration hashed Map.
import java.util.*;
import net.mindview.util.*;
 
public class SimpleHashMap<K,V> extends AbstractMap<K,V> {
 // Choose a prime number for the hash table size, to achieve a uniform distribution:
 static final int SIZE = 997;
 // You can't have a physical array of generics, but you can upcast to one:
 @SuppressWarnings("unchecked")
 LinkedList<MapEntry<K,V>>[] buckets =
  new LinkedList[SIZE];
 public V put(K key, V value) {
  V oldValue = null;
  int index = Math.abs(key.hashCode()) % SIZE;
  if(buckets[index] == null)
   buckets[index] = new LinkedList<MapEntry<K,V>>();
  LinkedList<MapEntry<K,V>> bucket = buckets[index];
  MapEntry<K,V> pair = new MapEntry<K,V>(key, value);
  boolean found = false;
  ListIterator<MapEntry<K,V>> it = bucket.listIterator();
  while(it.hasNext()) {
   MapEntry<K,V> iPair = it.next();
   if(iPair.getKey().equals(key)) {
    oldValue = iPair.getValue();
    it.set(pair); // Replace old with new
    found = true;
    break;
   }
  }
  if(!found)
   buckets[index].add(pair);
  return oldValue;
 }
 public V get(Object key) {
  int index = Math.abs(key.hashCode()) % SIZE;
  if(buckets[index] == null) return null;
  for(MapEntry<K,V> iPair : buckets[index])
   if(iPair.getKey().equals(key))
    return iPair.getValue();
  return null;
 }
 public Set<Map.Entry<K,V>> entrySet() {
  Set<Map.Entry<K,V>> set= new HashSet<Map.Entry<K,V>>();
  for(LinkedList<MapEntry<K,V>> bucket : buckets) {
   if(bucket == null) continue;
   for(MapEntry<K,V> mpair : bucket)
    set.add(mpair);
  }
  return set;
 }
 public static void main(String[] args) {
  SimpleHashMap<String,String> m =
   new SimpleHashMap<String,String>();
  m.putAll(Countries.capitals(25));
  System.out.println(m);
  System.out.println(m.get("ERITREA"));
  System.out.println(m.entrySet());
 }
}

SimpleHashMap構造一個hash表來存儲key,hash函數是取模運算Math.abs(key.hashCode()) % SIZE,采用鏈表法解決hash沖突;buckets的每一個槽位對應存放具有相同(hash后)index值的Map.Entry,如下圖所示:

java中HashMap的原理分析

JDK的HashMap的實現原理與之相類似,其采用鏈地址的hash表table存儲Map.Entry:

?
1
2
3
4
5
6
7
8
9
10
11
12
/**
 * The table, resized as necessary. Length MUST Always be a power of two.
 */
transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;
 
static class Entry<K,V> implements Map.Entry<K,V> {
  final K key;
  V value;
  Entry<K,V> next;
  int hash;
  
}

Map.Entry的index是對key的hashcode進行hash后所得。當要get key對應的value時,則對key計算其index,然后在table中取出Map.Entry即可得到,具體參看代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public V get(Object key) {
  if (key == null)
    return getForNullKey();
  Entry<K,V> entry = getEntry(key);
 
  return null == entry ? null : entry.getValue();
}
 
final Entry<K,V> getEntry(Object key) {
  if (size == 0) {
    return null;
  }
 
  int hash = (key == null) ? 0 : hash(key);
  for (Entry<K,V> e = table[indexFor(hash, table.length)];
     e != null;
     e = e.next) {
    Object k;
    if (e.hash == hash &&
      ((k = e.key) == key || (key != null && key.equals(k))))
      return e;
  }
  return null;
}

可見,hashcode直接影響HashMap的hash函數的效率——好的hashcode會極大減少hash沖突,提高查詢性能。同時,這也解釋開篇提出的兩個問題:如果自定義的類做HashMap的key,則hashcode的計算應涵蓋構造函數的所有字段,否則有可能得到null。

延伸 · 閱讀

精彩推薦
552
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25
主站蜘蛛池模板: 黄色特级片黄色特级片 | 青青草好吊色 | 国产精品久久久久久久久久久久久久久久 | 久久久精品视频国产 | 久久一级 | 日本免费成人网 | 欧美aaaaaaaa| 800av凹凸 | 中午字幕无线码一区2020 | 午夜亚洲影院 | 国产精品久久久久久久久久大牛 | 国产精品久久久久久影视 | 欧美黄成人免费网站大全 | av观看国产| 成年性羞羞视频免费观看无限 | 91看片免费在线观看 | 亚洲视频黄| 日韩黄色免费电影 | av黄色片网站 | 日日做夜夜操 | 一二区电影 | 欧美a在线观看 | 国产九色在线播放九色 | 欧美日韩国产精品 | 日韩在线视频免费播放 | 中文字幕免费在线观看视频 | 成人在线网站 | 国产精品一二区 | 有兽焉免费动画 | 色人阁五月天 | 久久中文免费 | 美女被免费网站在线软件 | www.91成人| 欧洲a级片 | 亚欧美一区二区 | 亚洲电影免费观看国语版 | 久久精品亚洲精品国产欧美kt∨ | 免费放黄网站在线播放 | 国产视频导航 | 精品亚洲午夜久久久久91 | v11av在线视频成人 |