周全解析java中的hashtable。本站提示廣大學習愛好者:(周全解析java中的hashtable)文章只能為提供參考,不一定能成為您想要的結果。以下是周全解析java中的hashtable正文
Hashtables供給了一個很有效的辦法可使運用法式的機能到達最好。
Hashtables(哈希表)在盤算機范疇中已不 是一個新概念了。它們是用來加速盤算機的處置速度的,用現今的尺度來處置,速度異常慢,而它們可讓你在查詢很多數據條目時,很快地找到一個特別的條目。 雖然古代的機械速度已快了幾千倍,然則為了獲得運用法式的最好機能,hashtables依然是個很有效的辦法。
假想一下,你有一個包括約一千筆記錄的數據文件??好比一個小企業的客戶記載還有一個法式,它把記載讀到內存中停止處置。每一個記載包括一個獨一的五 位數的客戶ID號、客戶名字、地址、帳戶節余等等。假定記載不是按客戶ID號次序分類的,所以,假如法式要將客戶號作為“key” 來查找一個特別的客戶記載,獨一的查找辦法就是持續地搜刮每一個記載。有時侯,它會很快找到你須要的記載;但有時侯,在法式找到你須要的記載前,它簡直已搜 索到了最初一筆記錄。假如要在1,000筆記錄中搜刮,那末查找任何一筆記錄都須要法式均勻查核500.5 ((1000 + 1 )/2)筆記錄。假如你常須要查找數據,你應當須要一個更快的辦法來找到一筆記錄。
一種加速搜刮的辦法就是把記載分紅幾段,如許,你就不消搜刮一個很年夜的列表了,而是搜刮幾個短的列表。關於我們數字式的客戶ID號,你可以建10個 列表??以0開首的ID號構成一個列表,以1開首的ID號構成一個列表,依此類推。那末要查找客戶ID號38016,你只須要搜刮以3開首的列表就好了。 假如有1,000筆記錄,每一個列表的均勻長度為100 (1,000筆記錄被分紅10個列表),那末搜刮一筆記錄的均勻比擬次數就降到了約50(見圖1)。
固然,假如約非常之一的客戶號是以0開首的,別的非常之一是以1開首的,等等,那末這類辦法會很合適。假如90%的客戶號以0開首,那末誰人列表就 會有900筆記錄,每次查找均勻須要停止 450次比擬。別的,法式須要履行的搜刮有90%都是針對以0開首的號碼的。是以,均勻比擬數就年夜年夜跨越簡略數學運算的規模了。
假如我們可以按如許一種方法在我們的列表平分配記載,情形就會好一些,即每一個列表約有雷同條目標記載,而不論鍵值中數字的散布。我們須要一種辦法能 夠把客戶號碼混雜到一路並更好地散布成果。例如,我們可以取號碼中的每位數,乘以某個年夜的數(跟著數字地位的分歧而分歧),然後將成果相加發生一個總數, 把這個數除以10,並將余數作為索引值(index)。當讀入記載時,法式在客戶號碼上運轉這個哈希(hash) 函數來肯定記載屬於哪一個列表。當用戶須要查詢時,將統一個哈希函數作為一個“key”用於客戶號碼,如許便可以搜刮准確的列表了。像如許的一個數據構造就 稱為一個哈希表(hashtable)。
Java中的Hashtables
Java包括兩個類,java.util.Hashtable 和java.util.HashMap,它們供給了一個多種用處的hashtable機制。這兩個類很類似,平日供給雷同的私有接口。但它們切實其實有一些主要的分歧點,我在前面會講到。
Hashtable和HashMap對象可讓你把一個key和一個value聯合起來,並用put() 辦法把這對key/value輸出到表中。然後你可以經由過程挪用get()辦法,把key作為參數來獲得這個value(值)。只需知足兩個根本的請求, key和value可所以任何對象。留意,由於key和value必需是對象,所以原始類型(primitive types)必需經由過程應用諸如Integer(int)的辦法轉換成對象。
為了將一個特定類的對象用做一個key,這個類必需供給兩個辦法,equals() 和 hashCode()。這兩個辦法在java.lang.Object中,所以一切的類都可以繼續這兩個辦法;然則,這兩個辦法在Object類中的完成普通沒甚麼用,所以你平日須要本身重載這兩個辦法。
Equals ()辦法把它的對象同另外一個對象停止比擬,假如這兩個對象代表雷同的信息,則前往true。該辦法也檢查並確保這兩個對象屬於雷同的類。假如兩個參照對象 是完整一樣的對象,Object.equals()前往true,這就解釋了為何這個辦法平日不是很合適的緣由。在年夜多半情形下,你須要一個辦法來一個 字段一個字段地停止比擬,所以我們以為代表雷同數據的分歧對象是相等的。
HashCode()辦法經由過程應用對象的內容履行一個哈希函數來生成一個int值。Hashtable和HashMap用這個值來算出一對key/value位於哪一個bucket(哈希元)(或列表)中。
作為例子,我們可以檢查一下String 類,由於它有本身的辦法來完成這兩個辦法。String.equals()對兩個String對象一個字符一個字符地停止比擬,假如字符串是雷同的,則前往true:
String myName = "Einstein";
// The following test is
// always true
if ( myName.equals("Einstein") )
{ ...
String.hashCode ()在一個字符串上運轉哈希函數。字符串中每一個字符的數字代碼都乘以31,成果取決於字符串中字符的地位。然後將這些盤算的成果相加,獲得一個總數。這個 進程仿佛很龐雜,然則它確保可以或許更好地散布值。它也證實了你在開辟你本身的hashCode()辦法時,可以或許走多遠,確信成果是獨一的。
例如,假定我要用一個hashtable來完成一個書的目次,把書的ISBN號碼作為搜刮鍵來停止搜刮。我可以用String類來承載細節,並預備好了equals()和hashCode()辦法(見列表1)。我們可以用put()辦法添加成對的key/value到hashtable中(見列表2)。
Put()辦法接收兩個參數,它們都屬於Object類型。第一個參數是key;第二個參數是value。Put()辦法挪用key的hashCode()辦法,用表中的列表數來除這個成果。把余數作為索引值來肯定該筆記錄添加到哪一個列表中。留意,key在表中是獨一的;假如你用一個曾經存在的key來挪用put(),婚配的條目就被修正了,是以它參照的是一個新的值,而舊的值被前往了(當key在表中不存在時,put()前往空值)。
要讀取表中的一個值,我們把搜刮鍵用於get()辦法。它前往一個轉換到准確類型的Object參照:
BookRecord br =
(BookRecord)isbnTable.get(
"0-345-40946-9");
System.out.println(
"Author: " + br.author
+ " Title: " + br.title);
另外一個有效的辦法是remove(),其用法同get()簡直一樣,它把條目從表中刪除,並前往給挪用法式。
你本身的類
假如你想把一個原始類型用做一個key,你必需創立一個一致類型的對象。例如,假如你想用一個整數key,你應當用結構器 Integer(int)從整數中生成一個對象。一切的封裝類??如Integer、Float和Boolean都把原始值看作是對象,它們重載了 equals()和hashCode() 辦法,是以,它們可以被用做key。JDK中供給的很多其它的類也是如許的(乃至Hashtable和HashMap類都完成它們本身的equals() 和hashCode()辦法),但你把任何類的對象用做hashtable keys前,應當檢查文件。檢查類的起源,看看equals()和hashCode()是若何完成的,也很有需要。例如,Byte、Character、 Short和Integer都前往所代表的整數值作為哈希碼。這能夠合適,也能夠不合適你的需求。
在Java中應用Hashtables
假如你想創立一個hashtable,這個hashtable應用你本身界說的一個類的對象作為key,那末你應當確信這個類的equals()和hashCode()辦法供給有效的值。起首檢查你擴大的類,肯定它的完成能否知足你的需求。假如沒有,你應當重載辦法。
任何equals()辦法的根本設計束縛是,假如傳遞給它的對象屬於統一個類,並且它的數據字段設定為表現異樣數據的值,那末它就應當前往 true。你也應當確信,假如傳遞一個空的參數給該辦法,那末你的代碼前往
false:public boolean equals(Object o)
{
if ( (o == null)
|| !(o instanceof myClass))
{
return false;
}
// Now compare data fields...
別的,在設計一個hashCode()辦法時,應當記住一些規矩。起首,該辦法必需為一個特定的對象前往雷同的值,而不論這個辦法被挪用了若干次 (固然,只需對象的內容在挪用之間沒有轉變,在將一個對象用做一個hashtable的key時,應當防止這一點)。第二,假如由你的equals()方 法界說的兩個對象是相等的,那末它們也必需生成雷同的哈希碼。第三,這更像是一個方針,而不是一個准繩,你應當想法設計辦法,使它為分歧的對象內容生成不 同的成果。假如偶然分歧的對象正好生成了雷同的哈希碼,這也沒關系。然則,假如該辦法只能前往規模在1到10的值,那末只能用10個列表,而不論在 hashtable中有若干個列表。
在設計equals()和hashCode()時,另外一個要記住的身分是機能成績。每次挪用put() 或get(),都包含挪用hashCode()來查找准確的列表,當get()掃描列表來查找key時,它為列表中的每一個元素挪用equals()。完成 這些辦法使它們盡量快而有用地運轉,特別當你盤算使你的類地下可用時,由於其它的用戶能夠想在履行速度很主要的情形下,在高機能的運用法式中應用你的 類。
Hashtable機能
影響hashtable功能的重要身分就是表中列表的均勻長度,由於均勻搜刮時光與這個均勻長度直接相干。很明顯, 要減小均勻長度,你必需增長hashtable中列表的數目;假如列表數目異常年夜,以致於年夜多半列表或一切列表只包括一筆記錄,你就會取得最好的搜刮效 率。但是,如許做能夠太甚分了。假如你的hashtable的列表數遠遠多於數據條目,那你就沒有需要做如許的內存消費了,而在一些情形下,人們也弗成能 接收如許的做法。
在我們後面的例子中,我們事後曉得我們有若干筆記錄1,000。曉得這點後,我們便可以決議我們的hashtable 應當包括若干個列表,以便殺青搜刮速度和內存應用效力之間最好的折衷方法。但是,在很多情形下,你事後不曉得你要處置若干筆記錄;數據被讀取的文件能夠會 赓續擴展,或許記載的數目能夠一天一寰宇產生很年夜的變更。
跟著條目標增長,Hashtable和HashMap類經由過程靜態地擴大表來處置這個成績。這兩個類都有接收表中列表最後數目的結構器,和一個作為參數的負載系數(load factor):
public Hashtable(
int initialCapacity,
float loadFactor)
public HashMap(
int initialCapacity,
float loadFactor)
將這兩個數相乘盤算出一個臨界值。每次給哈希表添加一個新的條目時,計數就被更新,當計數跨越臨界值時,表被從新設置(rehash)。(列表數目 增長到之前數目的兩倍加1,一切的條目轉移到准確的列表中。)缺省的結構器設定最後的容量為11,負載系數是0.75,所以臨界值是8。當第九筆記錄被添 加到表中時,就從新調劑哈希表,使其有23個列表,新的臨界值將是17(23*0.75的整數部門)。你可以看到,負載系數是哈希表中均勻列表數目的上 限,這就意味著,在缺省情形下,哈希表很少會有很多包括不只一筆記錄的列表。比擬我們最後的例子,在誰人例子中,我們有1,000筆記錄,散布在10個列 表中。假如我們用缺省值,這個表將會擴大到含有1,500多個列表。但你可以掌握這點。假如用負載系數相乘的列表數目年夜於你處置的條目數,那末表永久不會 重制,所以我們可以仿效上面的例子:
// Table will not rehash until it
// has 1,100 entries (10*110):
Hashtable myHashTable =
new Hashtable(10, 110.0F);
你能夠不想這麼做,除非你沒無為空的列表節儉內存,並且不介懷額定的搜刮時光,這能夠在嵌入體系中會湧現這類情形。但是,這類辦法能夠很有效,由於從新設置很占用盤算時光,而這類辦法可以包管永久不會產生從新設置這類情形。
留意,固然挪用put()可使表增年夜(列表數目增長),挪用remove()不會有相反的成果。所以,假如你有一個年夜的表,並且從中刪除年夜部門條目,成果你會有一個年夜的然則年夜部門是空的表。
Hashtable和HashMap
Hashtable和HashMap類有三個主要的分歧的地方。第一個分歧重要是汗青緣由。Hashtable是基於陳腐的Dictionary類的,HashMap是Java 1.2引進的Map接口的一個完成。
或許最主要的分歧是Hashtable的辦法是同步的,而HashMap的辦法不是。這就意味著,固然你可以不消采用任何特別的行動便可以在一個多 線程的運用法式頂用一個Hashtable,但你必需異樣地為一個HashMap供給外同步。一個便利的辦法就是應用Collections類的靜態的 synchronizedMap()辦法,它創立一個線程平安的Map對象,並把它作為一個封裝的對象來前往。這個對象的辦法可讓你同步拜訪潛伏的HashMap。這麼做的成果就是當你不須要同步時,你不克不及割斷Hashtable中的同步(好比在一個單線程的運用法式中),並且同步增長了許多處置費用。
第三點分歧是,只要HashMap可讓你將空值作為一個表的條目標key或value。HashMap中只要一筆記錄可所以一個空的key,但任 意數目的條目可所以空的value。這就是說,假如在表中沒有發明搜刮鍵,或許假如發明了搜刮鍵,但它是一個空的值,那末get()將前往null。假如 有需要,用containKey()辦法來差別這兩種情形。
一些材料建議,當須要同步時,用Hashtable,反之用HashMap。然則,由於在須要時,HashMap可以被同步,HashMap的功效 比Hashtable的功效更多,並且它不是基於一個陳腐的類的,所以有人以為,在各類情形下,HashMap都優先於Hashtable。
關於Properties
有時侯,你能夠想用一個hashtable來映照key 的字符串到value的字符串。DOS、Windows和Unix中的情況字符串就有一些例子,如key的字符串PATH被映照到value的字符串C: \WINDOWS;C:\WINDOWS\SYSTEM。Hashtables是表現這些的一個簡略的辦法,但Java供給了別的一種辦法。
Java.util.Properties類是Hashtable的一個子類,設計用於String keys和values。Properties對象的用法同Hashtable的用法相象,然則類增長了兩個節儉時光的辦法,你應當曉得。
Store()辦法把一個Properties對象的內容以一種可讀的情勢保留到一個文件中。Load()辦法正好相反,用來讀取文件,並設定Properties對象來包括keys和values。
留意,由於Properties擴大了Hashtable,你可以用超類的put()辦法來添加不是String對象的keys和values。這是弗成取的。別的,假如你將store()用於一個不包括String對象的Properties對象,store()將掉敗。作為put()和get()的替換,你應當用setProperty()和getProperty(),它們用String參數。
好了,我願望你如今可以曉得若何用hashtables來加快你的處置了