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程式設計思想(2nd)學習筆記(7) (轉)Java程式設計筆記
- Java程式設計思想(2nd)學習筆記(6) (轉)Java程式設計筆記
- Java程式設計思想(2nd)學習筆記(8)-2 (轉)Java程式設計筆記
- Java程式設計思想(2nd)學習筆記(8)-1 (轉)Java程式設計筆記
- Java程式設計思想學習筆記1 - 內部類Java程式設計筆記
- 《java程式設計思想》筆記1Java程式設計筆記
- java 程式設計思想的學習筆記 - 第一章Java程式設計筆記
- Java程式設計思想學習筆記4 - 序列化技術Java程式設計筆記
- Java 程式設計思想筆記:Learn 10Java程式設計筆記
- Go學習筆記:關於Java、Python、Go程式設計思想的不同Go筆記JavaPython程式設計
- 《Java程式設計思想》筆記08——持有物件Java程式設計筆記物件
- 《Java程式設計思想》讀書筆記一Java程式設計筆記
- 讀書筆記-Java程式設計思想-03筆記Java程式設計
- 《Java程式設計思想》筆記07——內部類Java程式設計筆記
- 《Java程式設計思想》筆記8.多型Java程式設計筆記多型
- 《Windows 程式設計》學習筆記(五) (轉)Windows程式設計筆記
- 《Windows 程式設計》學習筆記(四) (轉)Windows程式設計筆記
- 《Windows 程式設計》學習筆記(三) (轉)Windows程式設計筆記
- C++程式設計思想筆記之四 (轉)C++程式設計筆記
- C++程式設計思想筆記之一 (轉)C++程式設計筆記
- C++程式設計思想筆記之三 (轉)C++程式設計筆記
- C++程式設計思想筆記之六 (轉)C++程式設計筆記
- C++程式設計思想筆記之二 (轉)C++程式設計筆記
- Java中的按位操作——Java程式設計思想筆記Java程式設計筆記
- Java學習筆記--網路程式設計SocketJava筆記程式設計
- Java JDK 9學習筆記JavaJDK筆記
- Java程式設計思想讀書筆記一:併發Java程式設計筆記
- Python學習筆記之 Python設計思想&設計原則Python筆記
- XML 程式設計思想: 學習物件後設資料(轉)XML程式設計物件
- 黑馬程式設計師——Java學習筆記之⑦——“網路程式設計”程式設計師Java筆記
- 《深入理解java虛擬機器》學習筆記9——併發程式設計(一)Java虛擬機筆記程式設計
- <<軟體設計學習筆記>> (轉)筆記
- SGI STL學習筆記(2):traits程式設計技法筆記AI程式設計
- 重學Java設計模式-學習筆記(1)Java設計模式筆記
- 網路程式設計學習筆記程式設計筆記
- 系統程式設計學習筆記程式設計筆記
- 《WebGL程式設計指南》學習筆記——2.使用< canvas >元素Web程式設計筆記Canvas
- 《圖解 Google V8》設計思想篇——學習筆記(一)圖解Go筆記