亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Java > 正文

Java提高篇-----HashTable

2019-11-06 06:17:57
字體:
來源:轉載
供稿:網友

學習java的同學注意了?。?! 學習過程中遇到什么問題或者想獲取學習資源的話,歡迎加入Java學習交流群,群號碼:523047986  我們一起學Java!

        有兩個類都提供了一個多種用途的hashTable機制,他們都可以將可以key和value結合起來構成鍵值對通過put(key,value)方法保存起來,然后通過get(key)方法獲取相對應的value值。一個是前面提到的HashMap,還有一個就是馬上要講解的HashTable。對于HashTable而言,它在很大程度上和HashMap的實現差不多,如果我們對HashMap比較了解的話,對HashTable的認知會提高很大的幫助。他們兩者之間只存在幾點的不同,這個后面會闡述。

        一、定義

        HashTable在Java中的定義如下:

[java] view plain copypublic class Hashtable<K,V>      extends Dictionary<K,V>      implements Map<K,V>, Cloneable, java.io.Serializable  

        從中可以看出HashTable繼承Dictionary類,實現Map接口。其中Dictionary類是任何可將鍵映射到相應值的類(如 Hashtable)的抽象父類。每個鍵和每個值都是一個對象。在任何一個 Dictionary 對象中,每個鍵至多與一個值相關聯。Map是"key-value鍵值對"接口。

        HashTable采用"拉鏈法"實現哈希表,它定義了幾個重要的參數:table、count、threshold、loadFactor、modCount。

        table:為一個Entry[]數組類型,Entry代表了“拉鏈”的節點,每一個Entry代表了一個鍵值對,哈希表的"key-value鍵值對"都是存儲在Entry數組中的。

        count:HashTable的大小,注意這個大小并不是HashTable的容器大小,而是他所包含Entry鍵值對的數量。

        threshold:Hashtable的閾值,用于判斷是否需要調整Hashtable的容量。threshold的值="容量*加載因子"。

        loadFactor:加載因子。

        modCount:用來實現“fail-fast”機制的(也就是快速失?。?。所謂快速失敗就是在并發集合中,其進行迭代操作時,若有其他線程對其進行結構性的修改,這時迭代器會立馬感知到,并且立即拋出ConcurrentModificationException異常,而不是等到迭代完成之后才告訴你(你已經出錯了)。

        二、構造方法

        在HashTabel中存在5個構造函數。通過這5個構造函數我們構建出一個我想要的HashTable。

[java] view plain copypublic Hashtable() {          this(11, 0.75f);      }  

        默認構造函數,容量為11,加載因子為0.75。

[java] view plain copypublic Hashtable(int initialCapacity) {          this(initialCapacity, 0.75f);      }  

        用指定初始容量和默認的加載因子 (0.75) 構造一個新的空哈希表。

[java] view plain copypublic Hashtable(int initialCapacity, float loadFactor) {          //驗證初始容量          if (initialCapacity < 0)              throw new IllegalArgumentException("Illegal Capacity: "+                                                 initialCapacity);          //驗證加載因子          if (loadFactor <= 0 || Float.isNaN(loadFactor))              throw new IllegalArgumentException("Illegal Load: "+loadFactor);            if (initialCapacity==0)              initialCapacity = 1;                    this.loadFactor = loadFactor;                    //初始化table,獲得大小為initialCapacity的table數組          table = new Entry[initialCapacity];          //計算閥值          threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);          //初始化HashSeed值          initHashSeedAsNeeded(initialCapacity);      }  

        用指定初始容量和指定加載因子構造一個新的空哈希表。其中initHashSeedAsNeeded方法用于初始化hashSeed參數,其中hashSeed用于計算key的hash值,它與key的hashCode進行按位異或運算。這個hashSeed是一個與實例相關的隨機值,主要用于解決hash沖突。

[java] view plain copy 在CODE上查看代碼片public Hashtable(Map<? extends K, ? extends V> t) {          //設置table容器大小,其值==t.size * 2 + 1          this(Math.max(2*t.size(), 11), 0.75f);          putAll(t);      }  

       %20三、主要方法        HashTable的API對外提供了許多方法,這些方法能夠很好幫助我們操作HashTable,但是這里我只介紹兩個最根本的方法:put、get。

        首先我們先看put方法:將指定 key 映射到此哈希表中的指定 value。注意這里鍵key和值value都不可為空。

[java] view%20plain copy public synchronized V put(K key, V value) {          // 確保value不為null          if (value == null) {              throw new NullPointerException();          }            /*          * 確保key在table[]是不重復的          * 處理過程:          * 1、計算key的hash值,確認在table[]中的索引位置          * 2、迭代index索引位置,如果該位置處的鏈表中存在一個一樣的key,則替換其value,返回舊值          */          Entry tab[] = table;          int hash = hash(key);    //計算key的hash值          int index = (hash & 0x7FFFFFFF) % tab.length;     //確認該key的索引位置          //迭代,尋找該key,替換          for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {              if ((e.hash == hash) && e.key.equals(key)) {                  V old = e.value;                  e.value = value;                  return old;              }          }            modCount++;          if (count >= threshold) {  //如果容器中的元素數量已經達到閥值,則進行擴容操作              rehash();              tab = table;              hash = hash(key);              index = (hash & 0x7FFFFFFF) % tab.length;          }            // 在索引位置處插入一個新的節點          Entry<K,V> e = tab[index];          tab[index] = new Entry<>(hash, key, value, e);          //容器中元素+1          count++;          return null;      }  

        put方法的整個處理流程是:計算key的hash值,根據hash值獲得key在table數組中的索引位置,然后迭代該key處的Entry鏈表(我們暫且理解為鏈表),若該鏈表中存在一個這個的key對象,那么就直接替換其value值即可,否則在將改key-value節點插入該index索引位置處。如下:

        首先我們假設一個容量為5的table,存在8、10、13、16、17、21。他們在table中位置如下:

        然后我們插入一個數:put(16,22),key=16在table的索引位置為1,同時在1索引位置有兩個數,程序對該“鏈表”進行迭代,發現存在一個key=16,這時要做的工作就是用newValue=22替換oldValue16,并將oldValue=16返回。

        在put(33,33),key=33所在的索引位置為3,并且在該鏈表中也沒有存在某個key=33的節點,所以就將該節點插入該鏈表的第一個位置。

        在HashTabled的put方法中有兩個地方需要注意:

        1、HashTable的擴容操作,在put方法中,如果需要向table[]中添加Entry元素,會首先進行容量校驗,如果容量已經達到了閥值,HashTable就會進行擴容處理rehash(),如下:

[java] view plain copy 在CODE上查看代碼片protected void rehash() {          int oldCapacity = table.length;          //元素          Entry<K,V>[] oldMap = table;            //新容量=舊容量 * 2 + 1          int newCapacity = (oldCapacity << 1) + 1;          if (newCapacity - MAX_ARRAY_SIZE > 0) {              if (oldCapacity == MAX_ARRAY_SIZE)                  return;              newCapacity = MAX_ARRAY_SIZE;          }                    //新建一個size = newCapacity 的HashTable          Entry<K,V>[] newMap = new Entry[];            modCount++;          //重新計算閥值          threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);          //重新計算hashSeed          boolean rehash = initHashSeedAsNeeded(newCapacity);            table = newMap;          //將原來的元素拷貝到新的HashTable中          for (int i = oldCapacity ; i-- > 0 ;) {              for (Entry<K,V> old = oldMap[i] ; old != null ; ) {                  Entry<K,V> e = old;                  old = old.next;                    if (rehash) {                      e.hash = hash(e.key);                  }                  int index = (e.hash & 0x7FFFFFFF) % newCapacity;                  e.next = newMap[index];                  newMap[index] = e;              }          }      }  

        在這個rehash()方法中我們可以看到容量擴大兩倍+1,同時需要將原來HashTable中的元素一一復制到新的HashTable中,這個過程是比較消耗時間的,同時還需要重新計算hashSeed的,畢竟容量已經變了。這里對閥值啰嗦一下:比如初始值11、加載因子默認0.75,那么這個時候閥值threshold=8,當容器中的元素達到8時,HashTable進行一次擴容操作,容量%20=%208%20*%202%20+%201%20=17,而閥值threshold=17*0.75%20=%2013,當容器元素再一次達到閥值時,HashTable還會進行擴容操作,一次類推。

        2、其實這里是我的一個疑問,在計算索引位置index時,HashTable進行了一個與運算過程(hash%20&%200x7FFFFFFF),為什么需要做一步操作,這么做有什么好處?如果哪位知道,望指導,LZ不勝感激?。∠旅媸怯嬎鉱ey的hash值,這里hashSeed發揮了作用。

[java] view%20plain copy private int hash(Object k) {          return hashSeed ^ k.hashCode();      }  

        相對于put方法,get方法就會比較簡單,處理過程就是計算key的hash值,判斷在table數組中的索引位置,然后迭代鏈表,匹配直到找到相對應key的value,若沒有找到返回null。

[java] view%20plain copy public synchronized V get(Object key) {          Entry tab[] = table;          int hash = hash(key);          int index = (hash & 0x7FFFFFFF) % tab.length;          for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {              if ((e.hash == hash) && e.key.equals(key)) {                  return e.value;              }          }          return null;      }  

        四、HashTable與HashMap的區別        HashTable和HashMap存在很多的相同點,但是他們還是有幾個比較重要的不同點。

        第一:我們從他們的定義就可以看出他們的不同,HashTable基于Dictionary類,而HashMap是基于AbstractMap。Dictionary是什么?它是任何可將鍵映射到相應值的類的抽象父類,而AbstractMap是基于Map接口的骨干實現,它以最大限度地減少實現此接口所需的工作。

        第二:HashMap可以允許存在一個為null的key和任意個為null的value,但是HashTable中的key和value都不允許為null。如下:

        當HashMap遇到為null的key時,它會調用putForNullKey方法來進行處理。對于value沒有進行任何處理,只要是對象都可以。

[java] view%20plain copy if (key == null)              return putForNullKey(value);  

        而當HashTable遇到null時,他會直接拋出NullPointerException異常信息。

[java] view%20plain copy 派生到我的代碼片if (value == null) {              throw new NullPointerException();          }  

        第三:Hashtable的方法是同步的,而HashMap的方法不是。所以有人一般都建議如果是涉及到多線程同步時采用HashTable,沒有涉及就采用HashMap,但是在Collections類中存在一個靜態方法:synchronizedMap(),該方法創建了一個線程安全的Map對象,并把它作為一個封裝的對象來返回,所以通過Collections類的synchronizedMap方法是可以我們你同步訪問潛在的HashMap。這樣君該如何選擇呢???

學習Java的同學注意了!??! 學習過程中遇到什么問題或者想獲取學習資源的話,歡迎加入Java學習交流群,群號碼:523047986  我們一起學Java!


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日本sm极度另类视频| 亚洲人成77777在线观看网| 91精品国产网站| 欧美一级大片在线免费观看| 欧美日韩激情视频8区| 亚洲国产婷婷香蕉久久久久久| 久久99国产精品自在自在app| 欧美精品18videos性欧美| 91免费看国产| 国产激情999| 国产精品久久久久久久久影视| 久久av在线看| 国产精品午夜国产小视频| 国产精品丝袜视频| 97精品一区二区视频在线观看| 在线观看视频99| 午夜剧场成人观在线视频免费观看| 激情亚洲一区二区三区四区| 成人午夜激情免费视频| 国产a∨精品一区二区三区不卡| 久久视频精品在线| 欧美性色19p| 北条麻妃一区二区三区中文字幕| 中文字幕欧美亚洲| 久久久免费高清电视剧观看| 国产精品丝袜一区二区三区| 久久久成人av| 欧美福利在线观看| 日韩在线免费视频| 中文在线资源观看视频网站免费不卡| 国产精品爱啪在线线免费观看| 一区二区三区四区视频| 中文字幕精品av| 精品国产欧美一区二区五十路| 国产一区二区视频在线观看| 欧美精品在线播放| 亚洲影院在线看| 在线观看视频亚洲| 日韩av综合网站| 午夜精品美女自拍福到在线| 亚州国产精品久久久| 精品国产一区二区三区久久狼5月| 成人a在线观看| 久久久影视精品| 91免费精品国偷自产在线| 国色天香2019中文字幕在线观看| 成人综合国产精品| 96精品视频在线| 久久人体大胆视频| 久久久久久久久网站| 综合国产在线观看| 日韩中文字幕在线看| 热99精品只有里视频精品| 亚洲精选中文字幕| 欧美激情日韩图片| 精品国产鲁一鲁一区二区张丽| 亚洲综合成人婷婷小说| 在线播放日韩av| 欧美激情一级二级| 热久久视久久精品18亚洲精品| 在线观看国产精品日韩av| 国产91精品高潮白浆喷水| 久久精品国产电影| 国产成人精品久久二区二区91| 色偷偷亚洲男人天堂| 精品一区电影国产| 成人免费淫片视频软件| 日韩欧美亚洲一二三区| 91久久综合亚洲鲁鲁五月天| 亚洲mm色国产网站| 亚洲第一网站男人都懂| 这里只有精品丝袜| 91久久国产婷婷一区二区| 日韩成人av一区| 日本国产欧美一区二区三区| 亚洲一区二区三区香蕉| 久久久久久久久久婷婷| 欧美大尺度在线观看| 91在线观看免费高清| 日韩国产欧美精品在线| 亚洲欧美一区二区三区情侣bbw| 欧美日韩国产综合视频在线观看中文| 欧美性猛交xxxx偷拍洗澡| 欧美国产日韩xxxxx| 91精品国产高清久久久久久| 九九热精品视频国产| 亚洲开心激情网| 国产精品成熟老女人| 欧美性猛交xxxx乱大交3| 久久99国产精品自在自在app| 亚洲国产成人精品一区二区| 亚洲欧美国产va在线影院| 国产精品亚洲网站| 欧美国产日产韩国视频| 久久伊人91精品综合网站| 日韩视频亚洲视频| 国产亚洲一区二区精品| 成人免费在线视频网站| 欧美巨猛xxxx猛交黑人97人| 亚洲欧美国产精品专区久久| 538国产精品一区二区免费视频| 日韩在线观看免费av| 亚洲福利视频网站| 久久久精品一区二区三区| 国产精品狼人色视频一区| www高清在线视频日韩欧美| 国产91成人在在线播放| 欧美电影免费看| 国产又爽又黄的激情精品视频| 青青久久aⅴ北条麻妃| 日本一欧美一欧美一亚洲视频| 亚洲欧美激情另类校园| 91tv亚洲精品香蕉国产一区7ujn| 国产欧美日韩综合精品| 91国偷自产一区二区三区的观看方式| 国产精品久久久久久亚洲调教| 92看片淫黄大片欧美看国产片| 北条麻妃一区二区三区中文字幕| 久久久最新网址| 亚洲性xxxx| 成人久久一区二区| 最新国产成人av网站网址麻豆| 久久天堂电影网| 日韩精品免费看| 欧美在线影院在线视频| 一区二区欧美亚洲| 国产欧美va欧美va香蕉在| 国产欧美精品在线播放| 2018中文字幕一区二区三区| 欧洲午夜精品久久久| 国产精品国模在线| 中文欧美在线视频| 黑人狂躁日本妞一区二区三区| 日韩在线免费观看视频| 亚洲欧美第一页| 国产精品免费一区| 国产丝袜一区视频在线观看| 亚洲高清在线观看| 欧美激情一区二区三级高清视频| 日韩在线播放一区| 亚洲韩国日本中文字幕| 精品少妇一区二区30p| 亚洲第一福利在线观看| 欧美精品亚州精品| 亚洲国模精品私拍| 国产欧美日韩免费看aⅴ视频| 色悠悠国产精品| 亚洲精品久久久久久久久久久久久| 色婷婷综合成人av| 日韩高清a**址| 国产精品久久久久秋霞鲁丝| 久久国产精品网站| 国产精品视频在线播放| 美女黄色丝袜一区| 国产精品美女无圣光视频| 成人午夜两性视频| 欧美理论在线观看| 91亚洲精品一区二区| 亚洲国产欧美在线成人app| 精品国产精品三级精品av网址| 日韩在线一区二区三区免费视频| 久久琪琪电影院| 欧美日韩国内自拍| 亚洲国模精品一区|