當前位置:成語大全網 - 書法字典 - Java中HashMap和TreeMap的區別

Java中HashMap和TreeMap的區別

首先,什麽是地圖?在數組中,我們通過數組下標索引其內容,而在映射中,我們通過對象索引對象。用於索引的對象叫做key,對應的對象叫做value,也就是我們通常所說的鍵值對。

HashMap通過hashcode快速搜索其內容,而TreeMap中的所有元素都保持壹定的固定順序。如果需要得到有序的結果,應該使用TreeMap(HashMap中元素的順序是不固定的)。

HashMap非線程安全樹圖非線程安全

線程安全

在Java中,線程安全壹般體現在兩個方面:

1,多個線程對同壹個java實例的訪問(讀取和修改)不會互相幹擾,這主要體現在關鍵字synchronized上。比如ArrayList和Vector,HashMap和Hashtable。

(後者在每個方法前都有壹個synchronized關鍵字)。如果interator中有壹個List對象,而其他線程刪除了壹個元素,問題就會出現。

2.每個線程都有自己的字段,不會在多個線程之間共享。主要體現在java.lang.ThreadLocal類中,沒有java關鍵字支持,比如static和transient。

1.抽象類和SortedMap接口

抽象地圖

抽象類:(HashMap繼承AbstractMap)重寫equals()和hashCode()方法,以確保兩個相等的映射返回相同的哈希代碼。如果兩個人

如果兩個映射大小相等,包含相同的鍵,並且每個鍵在兩個映射中具有相同的值,則這兩個映射相等。映射的散列碼是映射元素的散列碼的總和,其中每個元素是

地圖的實現。進入界面。因此,無論映射的內部順序如何,兩個相等的映射都會報告相同的哈希代碼。

SortedMap接口:(TreeMap

繼承自SortedMap)它用於保持鍵的有序。SortedMap接口為圖像的視圖(子集)提供訪問方法,包括兩個端點。除了排序對映射起作用。

鍵,處理SortedMap與處理SortedSet相同。添加到SortedMap實現類中的元素必須實現Comparable接口,否則必須給出它。

的構造函數提供了比較器接口的實現。TreeMap類是它唯壹的實現。

2.兩種傳統的Map實現

HashMap:基於哈希表的實現。HashCode()和equals()是用HashMap需要的key類明確定義的[hashCode()和equals()可以重寫]。為了優化HashMap空間的使用,可以調整初始容量和裝載因子。

(1)HashMap():構建壹個空散列圖像。

(2)HashMap(Map m):構建壹個hash映像,將映像m的所有映射相加。

(3)HashMap(int initialCapacity):構建壹個特定容量的空哈希映像。

(4) HashMap (int initial capacity,float load factor):構建壹個具有特定容量和負載因子的空哈希映像。

TreeMap:基於紅黑樹的實現。TreeMap沒有調整選項,因為樹總是處於平衡狀態。

(1)TreeMap():構建壹個空的圖像樹。

(2)TreeMap(Map m):建立壹棵圖像樹,並添加圖像m中的所有元素。

(3)TreeMap(比較器c):構建圖像樹,使用特定的比較器對關鍵詞進行排序。

(4)TreeMap(SortedMap s):構建壹棵圖像樹,將圖像樹S中的所有圖相加,使用與有序圖像S相同的比較器進行排序。

3.兩種常規地圖性能

HashMap:適用於在地圖中插入、刪除和定位元素。

Treemap:適合以自然順序或自定義順序遍歷鍵。

總結

HashMap通常比TreeMap快(由於樹和哈希表的數據結構),所以建議更多地使用HashMap,只有在需要對映射進行排序時才使用TreeMap。

進口?Java . util . hashmap;?

進口?Java . util . hashtable;?

進口?Java . util . iterator;?

進口?Java . util . map;?

進口?Java . util . treemap;?

公共?班級?HashMaps?{?

公共?靜電?作廢?main(String[]?args)?{?

地圖& lt弦,?字符串& gt?地圖?=?新的?HashMap & lt弦,?字符串& gt();?

map.put("a ",“AAA”);?

map.put("b ",“BBB”);?

map.put("c ",“CCC”);?

map.put("d ",“DDD”);?

叠代器& lt字符串& gt?叠代器?=?map.keySet()。叠代器();?

什麽時候?(iterator.hasNext())?{?

對象?鑰匙?=?iterator . next();?

system . out . println(" map . get(key)?是嗎?:"?+?map . get(key));?

}?

//?定義HashTable進行測試?

哈希表& lt字符串,?字符串& gt?tab?=?新的?哈希表& lt字符串,?字符串& gt();?

tab.put("a ",“AAA”);?

tab.put("b ",“BBB”);?

tab.put("c ",“CCC”);?

tab.put("d ",“DDD”);?

叠代器& lt字符串& gt?叠代器_1?=?tab.keySet()。叠代器();?

什麽時候?(iterator_1.hasNext())?{?

對象?鑰匙?=?iterator _ 1 . next();?

system . out . println(" tab . get(key)?是嗎?:"?+?tab . get(key));?

}?

樹形圖& lt弦,?字符串& gt?tmp?=?新的?樹形圖& lt字符串,?字符串& gt();?

tmp.put("a ",“AAA”);?

tmp.put("b ",“BBB”);?

tmp.put("c ",“CCC”);?

tmp.put("d ",“疾控中心”);?

叠代器& lt字符串& gt?叠代器_2?=?tmp.keySet()。叠代器();?

什麽時候?(iterator_2.hasNext())?{?

對象?鑰匙?=?iterator _ 2 . next();?

system . out . println(" tmp . get(key)?是嗎?:"?+?tmp . get(key));?

}?

}?

}運行結果如下:

map.get(鍵)是:ddd

map.get(key)是:bbb

map.get(key)是:ccc

map.get(key)是:aaa

tab.get(key)是:bbb

tab.get(鍵)是:aaa

tab.get(鍵)是:ddd

tab.get(key)是:ccc

tmp.get(鍵)是:aaa

tmp.get(key)是:bbb

tmp.get(key)是:ccc

tmp.get(鍵)是:cdc

HashMap結果是無序的,而TreeMap輸出結果是有序的。

接下來,我們將進入本文的主題。讓我們舉壹個例子來說明如何使用HashMap:

進口?Java . util . *;?

公共?班級?Exp1?{?

公共?靜電?作廢?main(String[]?args){?

HashMap?h 1 =新?HashMap();?

隨機?r 1 =新?random();?

為了什麽?(int?I = 0;我& lt1000;i++){?

整數?t =新?整數(r 1 . nextint(20));?

如果?(h1.containsKey(t))?

((Ctime)h1.get(t))。count++;?

不然呢?

h1.put(t,新的?ctime());?

}?

system . out . println(h 1);?

}?

}?

班級?Ctime{?

int?count = 1;?

公共?字符串?toString(){?

回歸?Integer.toString(計數);?

}?

}在HashMap中,通過get()獲取值,通過put()插入值,ContainsKey()用於檢查對象是否已經存在。可以看出,與ArrayList的操作相比,HashMap除了通過鍵索引其內容外,其他方面差別不大。

前面說過,HashMap是基於HashCode的,所有對象的超類對象中都有HashCode()方法,但是它和equals方法壹樣,並不適用於所有情況,所以我們需要重新編寫自己的HashCode()方法。這裏有壹個例子:

進口?Java . util . *;?

公共?班級?Exp2?{?

公共?靜電?作廢?main(String[]?args){?

HashMap?h2 =新?HashMap();?

為了什麽?(int?I = 0;我& lt10;i++)?

h2.put(新?元素(I),?新的?figure out());?

system . out . println(" H2:");?

System.out.println("Get?那個?結果?為了什麽?元素:“);?

元素?測試=新?元素(5);?

如果?(h2.containsKey(test))?

system . out . println((figure out)H2 . get(test));?

不然呢?

System.out.println("不是?發現”);?

}?

}?

班級?元素{?

int?號碼;?

公共?元素(int?n){?

數字= n;?

}?

}?

班級?算出{?

隨機?r =新?random();?

布爾?possible = r . nextdouble()& gt;0.5;?

公共?字符串?toString(){?

如果?(可能)?

回歸?“好的!”;?

不然呢?

回歸?“不可能!”;?

}?

}在這個例子中,Element用於索引對象Figureout,也就是說,Element是鍵,Figureout是值。在圖中

機器生成壹個浮點數,如果它大於0.5,打印“OK!”,否則打印“不可能!”。然後檢查對應於元素(3)的計算結果。

怎麽樣?

原來無論妳跑多少次,結果都是“沒找到”。也就是說,索引元素(3)不在HashMap中。這怎麽可能呢?

起源

我們慢慢說:元素的HashCode方法繼承自對象,對象中HashCode方法返回的HashCode對應當前位置。

地址,也就是說,對於不同的對象,即使它們的內容完全相同,HashCode()返回的值也會不同。這實際上違背了我們的意圖。因為我們在使用

HashMap,妳想通過使用相同內容的對象索引得到相同的目標對象,這就需要HashCode()在此時返回相同的值。在上面的例子中,我們期望

新元素(i) (i=5)和

Elementtest=newElement(5)相同,但實際上是兩個不同的對象。雖然它們的內容相同,但是它們在內存中的地址不同。所以這很自然

是的,上面的程序無法得到我們想象的結果。對元素類進行了以下更改:

班級?元素{?

int?號碼;?

公共?元素(int?n){?

數字= n;?

}?

公共?int?hashCode(){?

回歸?號碼;?

}?

公共?布爾?等於(對象?o){?

回歸?(o?instanceof?元素)?& amp& amp?(number==((Element)o)。號);?

}?

}這裏元素覆蓋了對象中的hashCode()和equals()方法。重寫hashCode(),使它的值為# as。

Hashcode返回,因此具有相同內容的對象將具有相同的hashcode。重寫equals()的目的是確定兩個鍵是否在HashMap中。

相等使得結果有意義(關於重寫equals()的內容,請參考我的另壹篇文章《對象類中的重寫方法》)。修改後的程序的結果如下:

h2:

獲取元素的結果:

不可能!

記住:如果妳想有效地使用HashMap,妳必須重寫它的HashCode()。

重寫HashCode()也有兩個原則:

[list=1]

您不必為每個不同的對象生成唯壹的hashcode,只要您的HashCode方法允許get()獲取put()放入的內容。即“不為壹”的原則。

生長

生成hashcode的算法使hashcode的值盡可能分散,不希望很多hashcode集中在壹個範圍內,有利於提高HashMap的性能。即“

分權原則”。至於第二個原則的具體原因,有興趣的人可以參考布魯斯·埃凱爾的思想。

Java,裏面有HashMap內部實現原理的介紹,這裏就不贅述了。

掌握了這兩條原則,妳就可以用HashMap編寫自己的程序了。

不知道大家有沒有註意到,java.lang.Object中提供的三個方法:clone()、equals()和hashCode()很典型,但是也有很多。

它們只是從對象的地址得到結果。這要求我們在自己的程序中重寫它們。事實上,java類庫已經在千千重寫了數千個這樣的方法。使用

面向對象的多態性覆蓋,Java的設計者優雅地構造了Java的結構,這也體現了Java是純OOP語言的特點。