1.定义一个Map接口,Entry<K,V>对象为Map的元素
package test;
public interface Map<K,V> {
V put(K k,V v);
V get(K k);
int size();
interface Entry<K,V>{
K getKey();
V getValue();
}
}
2.主要实现了put,get以及size()方法
package test;
public class HashMap<K, V> implements Map<K, V> {
Entry[] table = null;
int size;
HashMap() {
table = new Entry[16];
}
/**
* 1.hashCode(k),算出哈希值
* 2.取余运算算出index索引值
* 3.是否有值,如果没有值则添加,有值则添加到链表中
*
* @param k
* @param v
* @return
*/
@Override
public V put(K k, V v) {
int index = hash(k);
System.out.println(k.hashCode());
if (table[index] == null) {
table[index] = new Entry(k, v, k.hashCode(), null);
size++;
} else {
table[index] = new Entry(k, v, k.hashCode(), table[index]);
}
return (V) table[index].getValue();
}
private int hash(K k) {
int i = k.hashCode() % 16;
return i > 0 ? i : Math.abs(i);
}
/**
* 1.通过k获取到hashCode值
* 2.算出index
* 3.判断k是否相等,如果相等则返回,如果不等则判断其他链表是否相等
*
* @param k
* @return
*/
@Override
public V get(K k) {
int hash = hash(k);
Entry<K, V> entry = table[hash];
return findValueByKey(entry, k);
}
private V findValueByKey(Entry<K, V> entry, K k) {
if (entry == null) {
return null;
}
if (entry.getKey().equals(k) || k == entry.getKey()) {
return (V) entry.getValue();
} else if (entry.next != null) {
return (V) findValueByKey(entry.next, k);
}
return null;
}
@Override
public int size() {
return size;
}
static class Entry<K, V> implements Map.Entry<K, V> {
K k;
V v;
int hashCode;
Entry<K, V> next;
public Entry(K k, V v, int hashCode, Entry<K, V> next) {
this.k = k;
this.v = v;
this.hashCode = hashCode;
this.next = next;
}
@Override
public K getKey() {
return this.k;
}
@Override
public V getValue() {
return this.v;
}
}
}
3.测试
package test;
public class test {
public static void main(String[] args) {
Map<String, Object> map = new HashMap<String,Object>();
map.put("lzf", "海淀");
map.put("zhx", "昌平");
map.put("wq", "朝阳");
int size = map.size();
System.out.println(map.get("lzf"));
System.out.println(map.get("zhx"));
System.out.println(map.get("wq"));
System.out.println("size = " + size);
}
}
4.结果
其中"zhx"和"wq"索引值相同出项hash冲突,按照头插法放入链表中.
hashMap和ArrayList其实差不多,arrayList自带索引值,而hashMap是通过算出key的hashCode在通过一系列的位运算得出hash值,hash值^table.length-1得到索引值.
为什么hashMap的容量要是2的幂次方
首先计算键值对的索引要满足两个要求:不能越界、均匀分布
而 h % length
(h根据key计算出来的哈希值)就能满足这一点,但是取模运算速度较慢。
容量为2的次幂时、而 h & (length-1)
刚好也。能满足,而且按位与运算速度很快。
所以最终结果我认为:HashMap容量为2的次幂 开始是为了提高计算索引速度,但在解决哈希冲突过高的过程中通过右移
+异或
打乱哈希值,使得哈希冲突大大减少