Java程式設計思想(2nd)學習筆記(9)-2 (轉)
一. HashMap的工作原理及實現
1. 如何實現一個Map
1.1 與Map相關的知識
1.1.1 Map.Entry介面
一個實現了Map.Entry介面的類代表的是一個Map中的條目(一個key-value pair)。所以一個Map中必須要有一個實現了Map.Entry介面的類,並用這個類來存放Map中的key-value pair。
1.1.2 public abstract Set entrySet()
1) entrySet()函式返回一個Set,並且Set中的每一個元素都是一個Map.Entry型別的。在entrySet()函式中要把Map中所有的key-value pair以Map.Entry封裝後存入Set中的。
2) 當對Map進行修改操作後,entrySet()函式都會被。所以對Map的修改也會產生對這個Set的修改。
3) 當用這個Set的iterator進行操作時,不能進行add和addAll的操作。
1.2 實現一個簡單的Map的例項
import .util.*;
/**:namespace prefix = o ns = "urn:schemas--com::office" />
* MPair類實現了Map.Entry
*/
class MPair
implements Map.Entry, Comparable{
key, value; //key和value分別用來存放Map中的key和value
MPair(Object k, Object v){
key = k;
value = v;
}
//下面方法實現了Map.Entry介面中的方法
public Object getKey() { return key; }
public Object getValue() { return value; }
public Object setValue(Object v){
Object result = value;
value = v;
return result;
}
//下面方法實現了Comparable介面中的方法
public boolean equals(Object o){
return key.equals(((MPair)o).key);
}
public int compareTo(Object rv){
return ((Comparable)key).compareTo(((MPair)rv).key);
}
}
class SlowMap extends AbstractMap{
private ArrayList
keys = new ArrayList(),
values = new ArrayList();
public Object put(Object key, Object value){
Object result = get(key);
if(!keys.contains(key)){ //(1)
keys.add(key);
values.add(value);
}
else
values.set(keys.indexOf(key), value);
return result;
}
public Object get(Object key){
if(!keys.contains(key)){
return null;
}
else
return values.get(keys.indexOf(key));
}
//用Mpair封裝Map中的key-value pair並存入Set中
public Set entrySet(){
Set entries = new HashSet();
Iterator
ki = keys.iterator(),
vi = values.iterator();
while(ki.hasNext())
entries.add(new MPair(ki.next(), vi.next()));
return entries;
}
}
public class ExplicitStatic{
public static void main(String[] args){
SlowMap m = new SlowMap();
for( int i=1; i<10; i++)
m.put("km" + i, "m" + i);
System.out.println(m);
}
}
在上面程式碼的(1)處,我們要從ArrayList中查詢出是否具有key值,而這個查詢過程線性查詢,且key不具任何順序,所以速度會很慢。
1.3 如何對Map用迭代器進行操作
其它容器可以透過iterator()函式來生成物件的迭代器,但Map是不能生成的。如果要用迭代器對Map進行操作,則要透過entrySet()函式。用entrySet()函式生成的迭代器不能對Map進行add和addAll的操作。
public class ExplicitStatic{
public static void main(String[] args){
HashMap m = new HashMap();
for( int i=1; i<10; i++)
m.put("km" + i, "m" + i);
System.out.println("User for l:");
for( int i=1; i<=m.size(); i++ )
System.out.println("km" + i + " = " + m.get("km" + i));
System.out.println("User Iterator loop:");
Iterator it = m.entrySet().iterator();
while(it.hasNext()){
Map.Entry entry = (Map.Entry)it.next();
System.out.println(entry.getKey() + " = " + entry.getValue());
}
}
}
2. 與HashMap相關的幾個函式
1) hashCode()函式
Object.hashCode()函式會為物件產生hash code。如果一個類沒有實現hashCode()函式,那麼在預設情況下將返回它的物件的地址。
2) equals()函式
Object.equals()在比較兩個物件時,比較的是兩個物件的記憶體地址。
3. HashMap的工作原理
3.1 用array來表現key的資訊。每個key的hashCode()函式會為key產生一個hash code,而key的hash code作為array的。如假設有一個名為bucket的arrsy,姥一個hash code為2的key就被索引到bucket[2],key所對應的值也在bucket[2]中。
3.1 由於array中存放的是value值,而HashMap的元素個數可以是無限的,所以array中的元素指向的不是某個key的value,而是指向具有相同的hash code的key的value值(也就是說指向的是一串values值)。如假設array被定義為LinkedList []bucket = new LinkedList[10],那麼bucket[2]中存放的是所有hash code值為2的key的value。
4. 自己實現一個簡單的HashMap及其原理
4.1 在put()方法中:
1) 首先透過key得出要插入的key-value pair的hash code,並這個hash code作為索引在陣列bucket中找出key所對應的元素。
2) 把要插入的key-value pair封裝成實現了Map.Entry介面的類的一個物件。
3) 在操作1)所找出的陣列元素(也是一個LinkedList)中檢視是否有與要插入的key-value pair的key相同的元素,如果有,則對之進行;如果無,則把要插入的key-value pair陣列元素中。
4.2 在get()方法中
1) 首先透過key得出要查詢的key-value pair的hash code,並這個hash code作為索引在陣列bucket中找出key所對應的元素。
2) 把要查詢的key-value pair的key封裝成實現了Map.Entry介面的類的一個物件。
3) 在操作1)所找出的陣列元素(也是一個LinkedList)中檢視是否有與要插入的key-value pair的key相同的元素,如果有,則返回key所對應的value;如果無,則返回一個null。
4.3 一個例項
import java.util.*;
/**
* MPair類實現了Map.Entry
*/
class MPair
implements Map.Entry, Comparable{
Object key, value;
MPair(Object k, Object v){
key = k;
value = v;
}
public Object getKey() { return key; }
public Object getValue() { return value; }
public Object setValue(Object v){
Object result = value;
value = v;
return result;
}
/**
* 當比較兩個MPair物件時,比較的是它們的key值
*/
public boolean equals(Object o){
return key.equals(((MPair)o).key);
}
public int compareTo(Object rv){
return (((Comparable)key).compareTo(((MPair)rv).key));
}
}
class SimpleHashMap extends AbstractMap{
private final static int SZ = 997;
private LinkedList[] bucket = new LinkedList[SZ];
/**
* 把key和value封裝成Map.Entry的實現類後插入到array中
*/
public Object put(Object key, Object value){
Object result = null;
//透過key得到要插入的key-value pair的hash code
int index = key.hashCode() % SZ;
if(index < 0) index = - index;
if(bucket[index] == null)
bucket[index] = new LinkedList();
//透過hash code找出要插入的key所對應的array中的元素
LinkedList pairs = bucket[index];
//把要插入的key-value pair封裝成MPair
MPair pair = new MPair(key, value);
ListIterator it = pairs.listIterator();
boolean found = false;
//檢查是否有與要插入的key相同的key存在,如果有,就對之進行更新
while(it.hasNext()){
Object iPair = it.next();
if(iPair.equals(iPair)){
result = ((MPair)iPair).getValue();
it.set(pair);
found = true;
break;
}
}
//如果無,則把新的key-value pair插入
if(!found)
bucket[index].add(pair);
return result;
}
public Object get(Object key){
int index = key.hashCode() % SZ;
if(index < 0) index = -index;
if(bucket[index] == null) return null;
LinkedList pairs = bucket[index];
ListIterator it = pairs.listIterator();
MPair match = new MPair(key, null);
while(it.hasNext()){
Object iPair = it.next();
if(iPair.equals(match))
return ((MPair)iPair).getValue();
}
return null;
}
public Set entrySet(){
Set entries = new HashSet();
for(int i=0; i if(bucket[i] == null) continue; Iterator it = bucket[i].iterator(); while(it.hasNext()) entries.add(it.next()); } return entries; } } public class ExplicitStatic{ public static void main(String[] args){ SimpleHashMap m = new SimpleHashMap(); for( int i=1; i<10; i++) m.put("km" + i, "m" + i); System.out.println(m); } }
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10748419/viewspace-963763/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Java程式設計思想學習筆記1 - 內部類Java程式設計筆記
- Java程式設計思想學習筆記4 - 序列化技術Java程式設計筆記
- Java 程式設計思想筆記:Learn 10Java程式設計筆記
- 《Java程式設計思想》讀書筆記一Java程式設計筆記
- 讀書筆記-Java程式設計思想-03筆記Java程式設計
- 《Java程式設計思想》筆記08——持有物件Java程式設計筆記物件
- 《Java程式設計思想》筆記8.多型Java程式設計筆記多型
- 《Java程式設計思想》筆記07——內部類Java程式設計筆記
- Python學習筆記之 Python設計思想&設計原則Python筆記
- Java JDK 9學習筆記JavaJDK筆記
- Linux程式設計學習筆記 | Linux IO學習[2] – 標準IOLinux程式設計筆記
- Linux學習/TCP程式設計學習筆記LinuxTCP程式設計筆記
- Java多執行緒程式設計筆記9:ReentrantReadWriteLockJava執行緒程式設計筆記
- 網路程式設計學習筆記程式設計筆記
- 重學Java設計模式-學習筆記(1)Java設計模式筆記
- Python3:物件導向程式設計學習筆記(2)Python物件程式設計筆記
- java程式設計師程式設計筆試基礎學習Java程式設計師筆試
- 程式設計基礎·Java學習筆記·物件導向(下)程式設計Java筆記物件
- Java併發程式設計學習筆記----執行緒池Java程式設計筆記執行緒
- 《圖解 Google V8》設計思想篇——學習筆記(一)圖解Go筆記
- Java設計模式學習筆記(一) 設計模式概述Java設計模式筆記
- Javascript高階程式設計 學習筆記JavaScript程式設計筆記
- ROS串列埠程式設計學習筆記ROS串列埠程式設計筆記
- 結構化程式設計--學習筆記程式設計筆記
- Golang 學習筆記——tun/tap 程式設計Golang筆記程式設計
- spark學習筆記--進階程式設計Spark筆記程式設計
- JAVA程式設計學習記錄(安裝Java)Java程式設計
- C#設計模式學習筆記:(9)組合模式C#設計模式筆記
- 四. 文字程式設計--Windows程式設計課程學習筆記程式設計Windows筆記
- JAVA語言程式設計思想Java程式設計
- 好程式設計師web前端培訓學習筆記Vue學習筆記一程式設計師Web前端筆記Vue
- RxJava2.x 學習筆記(一)函數語言程式設計RxJava筆記函數程式設計
- Vue學習筆記(九):元件化程式設計Vue筆記元件化程式設計
- python程式設計學習筆記⑦-1函式Python程式設計筆記函式
- 好程式設計師學習筆記:函式程式設計師筆記函式
- 設計模式學習筆記設計模式筆記
- 學習筆記-設計模式筆記設計模式
- Java設計模式學習筆記(五) 單例模式Java設計模式筆記單例
- 好程式設計師web前端培訓學習筆記Vue學習筆記之二程式設計師Web前端筆記Vue