国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

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

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Java源碼角度分析HashMap用法

Java源碼角度分析HashMap用法

2021-03-14 13:41Leesire Java教程

這篇文章主要介紹了Java源碼角度分析HashMap用法,具有一定借鑒價值,需要的朋友可以參考下

HashMap

優點:超級快速的查詢速度,時間復雜度可以達到O(1)的數據結構非HashMap莫屬。動態的可變長存儲數據(相對于數組而言)。

缺點:需要額外計算一次hash值,如果處理不當會占用額外的空間。

—HashMap如何使用—

平時我們使用hashmap如下

?
1
2
3
Map<Integer,String> maps=new HashMap<Integer,String>();  
maps.put(1, "a");  
maps.put(2, "b");

上面代碼新建了一個HashMap并且插入了兩個數據,這里不接受基本數據類型來做K,V

如果這么寫的話,就會出問題了:

?
1
Map<int,double> maps=new HashMap<int,double>();

我們為什么要這樣使用呢?請看源碼

?
1
2
3
public class HashMap<K,V> 
  extends AbstractMap<K,V> 
  implements Map<K,V>, Cloneable, Serializable

這是HashMap實現類的定義。

—HashMap是一個動態變長的數據結構—

在使用HashMap的時候,為了提高執行效率,我們往往會設置HashMap初始化容量:

?
1
Map<String,String> rm=new HashMap<String,String>(2)

或者使用guava的工具類Maps,可以很方便的創建一個集合,并且,帶上合適的大小初始化值。

?
1
Map<String, Object> map = Maps.newHashMapWithExpectedSize(7);

那么為什么要這樣使用呢?我們來看他們的源碼構造函數。

未帶參的構造函數:

?
1
2
3
4
5
6
public HashMap() {  
    this.loadFactor = DEFAULT_LOAD_FACTOR;  
    threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);  
    table = new Entry[DEFAULT_INITIAL_CAPACITY];  
    init();  
  }

public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR;
threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
table = new Entry[DEFAULT_INITIAL_CAPACITY];
init();
}

?
1
2
3
4
5
6
7
8
9
10
/**
   * Constructs an empty <tt>HashMap</tt> with the specified initial
   * capacity and the default load factor (0.75).
   *
   * @param initialCapacity the initial capacity.
   * @throws IllegalArgumentException if the initial capacity is negative.
   */
  public HashMap(int initialCapacity) {
    this(initialCapacity, DEFAULT_LOAD_FACTOR);
  }

名詞解釋:

?
1
2
3
DEFAULT_LOAD_FACTOR  //默認加載因子,如果不制定的話是0.75 
DEFAULT_INITIAL_CAPACITY //默認初始化容量,默認是16 
threshold //閾(yu)值 根據加載因子和初始化容量計算得出 ,<span style="color: rgb(54, 46, 43); font-family: "microsoft yahei";">threshold表示當HashMap的size大于threshold時會執行resize操作。

因此我們知道了,如果我們調用無參數的構造方法的話,我們將得到一個16容量的數組。

所以問題就來了:如果初始容量不夠怎么辦?

數組是定長的,如何用一個定長的數據來表示一個不定長的數據呢,答案就是找一個更長的,但是在resize的時候是很降低效率的。所以我們建議HashMap的初始化的時候要給一個靠譜的容量大小。

—HashMap的Put方法—

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public V put(K key, V value) { 
    if (key == null) //鍵為空的情況,HashMap和HashTable的一個區別 
      return putForNullKey(value); 
    int hash = hash(key.hashCode()); //根據鍵的hashCode算出hash值 
    int i = indexFor(hash, table.length); //根據hash值算出究竟該放入哪個數組下標中 
    for (Entry<K,V> e = table[i]; e != null; e = e.next) {//整個for循環實現了如果存在K那么就替換V 
      Object k; 
      if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { 
        V oldValue = e.value; 
        e.value = value; 
        e.recordAccess(this); 
        return oldValue; 
      
    
  
    modCount++;//計數器 
    addEntry(hash, key, value, i); //添加到數組中 
    return null
  }

如果插入的數據超過現有容量就會執行

?
1
addEntry(hash, key, value, i);
?
1
2
3
4
5
6
void addEntry(int hash, K key, V value, int bucketIndex) {  
Entry<K,V> e = table[bucketIndex];  
    table[bucketIndex] = new Entry<K,V>(hash, key, value, e);  
    if (size++ >= threshold)  
     <span style="color:#ff0000;"><strong> resize(2 * table.length);
}

這里顯示了如果當前 size++ >threshold 的話那么就會擴展當前的size的兩倍,執行resize(2*table.length),那么他們是如何擴展的呢?

?
1
2
3
4
5
6
7
8
9
10
11
12
13
void resize(int newCapacity) {  
    Entry[] oldTable = table;  
    int oldCapacity = oldTable.length;  
    if (oldCapacity == MAXIMUM_CAPACITY) {  
      threshold = Integer.MAX_VALUE;  
      return;  
    }  
  
    Entry[] newTable = new Entry[newCapacity]; <span style="color: rgb(51, 51, 51); font-family: Arial;">new 一個新的數組,</span>
    <strong> <span style="color:#ff0000;">transfer(newTable);</span> </strong> //將就數組轉移到新的數組中
    table = newTable;  
    threshold = (int)(newCapacity * loadFactor);  //重新計算容量
  }

對于轉移數組transfer是如何轉移的呢?

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void transfer(Entry[] newTable) {  
    Entry[] src = table;  
    int newCapacity = newTable.length;  
    for (int j = 0; j < src.length; j++) {  
      Entry<K,V> e = src[j];  
      if (e != null) {  
        src[j] = null;  
        do {  
          Entry<K,V> next = e.next;  
          int i = <strong><span style="color:#ff0000;">indexFor(e.hash, newCapacity);  //根據hash值個容量重新計算下標</span></strong>
          e.next = newTable[i];  
          newTable[i] = e;  
          e = next;  
        } while (e != null);  
      }  
    }  
  }

—hashmap擴容額外執行次數—

因此如果我們要添加一個1000個元素的hashMap,如果我們用默認值那么我么需要額外的計算多少次呢

當大于16*0.75=12的時候,需要從新計算12次

當大于16*2*0.75=24的時候,需要額外計算24次

……

當大于16*n*0.75=768的時候,需要額外計算768次

所以我們總共在擴充過程中額外計算12+24+48+……+768次

因此強力建議我們在項目中如果知道范圍的情況下,我們應該手動指定初始大小像這樣:

?
1
Map<Integer,String> maps=new HashMap<Integer,String>(1000);

總結:這就是為什么當hashmap使用過程中如果超出 初始容量后他的執行效率嚴重下降的原因。

以上就是本文關于Java源碼角度分析HashMap用法的全部內容,希望對大家有所幫助。感興趣的朋友可以繼續參閱本站其他相關專題,如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!

原文鏈接:http://blog.csdn.net/lee_sire/article/details/53424735

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 日韩中文在线 | 国产福利在线观看 | 久久只有精品 | 国产黄色av网站 | 婷婷91| 亚洲成人日韩在线 | 欧美在线观看视频 | 欧美成人激情视频 | 国产资源在线播放 | 国产精品久久久久久久久免费桃花 | 在线观看一区二区三区视频 | 欧美顶级毛片在线播放 | 国产精品第一国产精品 | 国产成人精品免费视频大全最热 | 91在线免费观看 | 久久久久久这里只有精品 | 日韩中文在线视频 | av在线播放网站 | 91视频网址 | 日韩无在线 | 91精品国产综合久久久久久丝袜 | 青青草成人在线 | 亚洲四区 | 久一久久 | 国产精品成人国产乱一区 | 亚洲综合视频 | 91精品国产日韩91久久久久久 | 国产色婷婷 | 亚洲视频在线观看 | 精品日韩一区二区 | 91成人在线 | 日韩欧美精品一区二区三区 | 国产在线看片 | 国产999精品久久久久久麻豆 | 伊人亚洲 | 精品黄色在线观看 | 动漫精品一区二区 | 秋霞av国产精品一区 | 91免费在线视频观看 | 中文字幕一区二区三 | 七七婷婷婷婷精品国产 |