实现自定义的HashSet之后HashMap也自然水到渠成了,作者的实现方法是以HashSet的方式来类比实现HashMap,而JavaAPI中标准的HashSet是基于HashMap的,因为Map中的keySet方法就是返回一个HashSet,所以只需要隐藏掉Value的相关操作,稍加改造就可以实现HashSet,减少代码冗余。
作者的这种方法虽然相对于标准的JavaAPI来说有些冗余,但十分利于学习和巩固基础,此种法方法原理就是将HashSet中存储的元素改为固定的Entry类,而Entry类是个泛型类,带有两个泛型K和V,分别代表key和value,闲话少叙,下面进入代码环节;
实现自定义HashMap的基本程序如下:
1.定义MyMap接口:
package A03.Hash;
public interface MyMap<K, V>
{
// 查找元素
boolean containsKey(K key);
// 查找元素
boolean containsValue(V value);
// 根据Key取出Value
V get(K key);
// 根据Key删除Value
void remove(K key);
// 获取映射表大小
int size();
// 是否为空
boolean isEmpty();
V put(K key, V value);
MySet<K> keySet();
MySet<V> values();
MySet<Entry<K, V>> entrySet();
class Entry<K, V>
{
K key;
V value;
public Entry(K key, V value)
{
this.key = key;
this.value = value;
}
public K getKey()
{
return key;
}
public V getValue()
{
return value;
}
@Override
public String toString()
{
return "[" + key + "=" + value + "]";
}
}
}
2.定义MyHashMap实现类
package A03.Hash;
import A01.LSQ.MyDLinkedList;
public class MyHashMap<K, V> implements MyMap<K, V>
{
private static int DEFAULT_INITIAL_CAPACITY = 10;
private static int MAXIMUM_CAPACITY = 1 << 30;
private int capacity;
private static float DEFAULT_MAX_LOAD_FACTOR = 0.75f;
private float loadFactorThreshold;
private int size = 0;
private MyDLinkedList<Entry<K, V>>[] table;
public MyHashMap()
{
this(DEFAULT_INITIAL_CAPACITY, DEFAULT_MAX_LOAD_FACTOR);
}
public MyHashMap(int initialCapacity)
{
this(initialCapacity, DEFAULT_MAX_LOAD_FACTOR);
}
public MyHashMap(int initialCapacity, float loadFactorThreshold)
{
if (initialCapacity > MAXIMUM_CAPACITY)
this.capacity = MAXIMUM_CAPACITY;
else
this.capacity = trimToPowerOf2(initialCapacity);
this.loadFactorThreshold = loadFactorThreshold;
table = new MyDLinkedList[capacity];
}
private int trimToPowerOf2(int initialCapacity)
{
int capacity = 1;
while (capacity < initialCapacity)
capacity <<= 1;
return capacity;
}
private static int supplementalHash(int h)
{
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
private int hash(int hashCode)
{
return supplementalHash(hashCode) & (capacity - 1);
}
private void rehash()
{
MySet<Entry<K, V>> set = entrySet();
capacity <<= 1;
System.out.println("capacity="+capacity);
table = new MyDLinkedList[capacity];
size = 0;
for (Entry<K, V> entry : set)
{
put(entry.getKey(), entry.getValue());
}
}
@Override
public String toString()
{
StringBuffer sb = new StringBuffer("[");
for (int i = 0; i < capacity; i++)
if (table[i] != null && table[i].size() > 0)
for (Entry<K, V> entry : table[i])
sb.append(entry);
sb.append("]");
return sb.toString();
}
@Override
public boolean isEmpty()
{
return size == 0;
}
@Override
public boolean containsKey(K key)
{
return get(key) != null;
}
@Override
public boolean containsValue(V value)
{
for (int i = 0; i < capacity; i++)
if (table[i] != null)
{
MyDLinkedList<Entry<K, V>> bucket = table[i];
for (Entry<K, V> entry : bucket)
if (entry.getValue().equals(value))
return true;
}
return false;
}
@Override
public V get(K key)
{
int bucketIndex = hash(key.hashCode());
if (table[bucketIndex] != null)
{
MyDLinkedList<Entry<K, V>> bucket = table[bucketIndex];
for (Entry<K, V> entry : bucket)
if (entry.getKey().equals(key))
return entry.getValue();
}
return null;
}
@Override
public V put(K key, V value)
{
int bucketIndex = hash(key.hashCode());
if (get(key) != null)
{
MyDLinkedList<Entry<K, V>> bucket = table[bucketIndex];
for (Entry<K, V> entry : bucket)
if (entry.getKey().equals(key))
{
V oldValue = entry.getValue();
entry.value = value;
return oldValue;
}
}
if (size >= capacity * loadFactorThreshold)
{
if (capacity == MAXIMUM_CAPACITY)
throw new RuntimeException();
rehash();
}
if (table[bucketIndex] == null)
table[bucketIndex] = new MyDLinkedList<>();
table[bucketIndex].add(new Entry<>(key, value));
size++;
return value;
}
@Override
public void remove(K key)
{
int bucketIndex = hash(key.hashCode());
if (table[bucketIndex] != null)
{
MyDLinkedList<Entry<K, V>> bucket = table[bucketIndex];
for (Entry<K, V> entry : bucket)
if (entry.getKey().equals(key))
{
bucket.remove(entry);
size--;
break;
}
}
}
@Override
public int size()
{
return size;
}
@Override
public MySet<K> keySet()
{
MySet<K> set = new MyHashSet<>();
for (int i = 0; i < capacity; i++)
if (table[i] != null)
{
MyDLinkedList<Entry<K, V>> list = table[i];
for (Entry<K, V> entry : list)
set.add(entry.getKey());
}
return set;
}
@Override
public MySet<V> values()
{
MySet<V> set = new MyHashSet<>();
for (int i = 0; i < capacity; i++)
if (table[i] != null)
{
MyDLinkedList<Entry<K, V>> list = table[i];
for (Entry<K, V> entry : list)
set.add(entry.getValue());
}
return set;
}
@Override
public MySet<Entry<K, V>> entrySet()
{
MySet<Entry<K, V>> set = new MyHashSet<>();
for (int i = 0; i < capacity; i++)
if (table[i] != null)
{
MyDLinkedList<Entry<K, V>> bucket = table[i];
for (Entry<K, V> entry : bucket)
set.add(entry);
}
return set;
}
}
多数代码与MyHashSet重复,属性值意义与MyHashSet相同,读者如果不懂可以先搞懂笔者的上一篇文章。