以陣列作為Hashtable的Key值
這星期在開發專案時,遇上了需要以陣列作為Hashtable的Key值的狀況,但直接以陣列當Key值加入Hashtable卻會發生get或containsKey無法正常運作的狀況,瀏覽了一下網路,發現只有少數在討論的網頁,下面是最接近的一篇討論:
http://www.velocityreviews.com/forums/t150335-arrays-as-key-in-a-hashmap.html
但實際測試後卻發現有以下問題
1. 利用Wrapper的例子只能先將陣列先轉換成Object陣列後才能使用
2. List(利用Arrays.asList做轉換)只有在物件陣列有效,如果是基礎型別(primitive type)的陣列,例如int[]及double[]就不適用
根據上述問題,如果將Wrapper加入泛型,也一樣無法解決基礎型別的問題,最後找到的通用解決方案如下:
1. 如果是Java基礎型別陣列或內建類別陣列(應該都已實作hashCode()及equals(Object obj)),則可利用下列Wrapper
class ArrayWrapper
{
Object[] m_array;
public ArrayWrapper(Object array) {
m_array = new Object[Array.getLength(array)];
for (int i=0;i<array.getlength(array);i++)
m_array[i] = Array.get(array, i);
}
public int hashCode() {
return Arrays.hashCode(m_array);
}
public boolean equals(Object o) {
ArrayWrapper aw = (ArrayWrapper)o;
return Arrays.equals(aw.m_array, this.m_array);
}
}
由於無論是基礎型別陣列或Java內建類別陣列皆可以Object當參數,所以不須轉換成Object陣列。當然在當參數傳入前或後,必須先確定(或檢查)是否為陣列。
2. 如果是自訂類別陣列,ㄧ定要實作hashCode()及equals(Object obj),再使用ArrayWrapper,例如下面的例子,
public class ObjectKey{
private String m_String;
private double m_Double;
private int m_Int;
public ObjectKey(String str, double dou, int i) {
this.m_String = str;
this.m_Double = dou;
this.m_Int = i;
}
public int hashCode(){
return this.m_String.hashCode();
}
public boolean equals(Object o) {
ObjectKey ok = (ObjectKey)o;
return ((this.m_String.equals(ok.m_String))
&& (this.m_Int == this.m_Int)
&& (this.m_Double == this.m_Double));
}
}
基本上hashCode的設計可以簡化,差別只會影響效能,但一定要有;equals就要看設計時如何定義兩物件相等,如上例子,如果認定m_String及m_Double相等即可,那就只要寫成
return ((this.m_String.equals(o.m_String)) && (this.m_Double == o.m_Double));
沒有留言:
張貼留言