HashMap就是Hash表的Map实现。 Hash表就是Hash数组,Map实现是指实现了Map接口。
HashMap的底层是基于数组和链表实现的,存储速度快的原因是因为它是通过计算散列码来决定存储的位置。HashMap中主要是通过key的hashCode来计算hash值的,只要hashCode相同,计算出来的hash值就一样。如果存储的对象对多了,就有可能不同的对象所算出来的hash值是相同的,这就出现了所谓的hash冲突。解决hash冲突的方法有很多,HashMap底层是通过链表来解决hash冲突的。
HashMap其实就是一个Entry数组,Entry对象中包含了键和值,其中next也是一个Entry对象,它就是用来处理hash冲突的,形成一个链表。
HashMap存放数据的时候,会先拿到key的hashCode值,对其进行hash运算,得到具体的hash值,然后根据hash值查找存放的位置index,找到存放的位置后,然后遍历table数组找到对应位置的entry,如果当前的key已经存在,且对比entry的hash值和key相同的话,那么就更新value值(在解决hash冲突的链表中,老的数据在链表的末端,端。),否则就将key和value值加到数组中。
hashmap原理视频:
视频中的源码(仿照hashmap的原理实现的源码):
仿照Map实现:
package com.dongnao.jack;
public interface DNMap<K, V> {
public V put(K k, V v);
public V get(K k);
public int size();
public interface Entry<K, V> {
public K getKey();
public V getValue();
}
}
仿照HashMap实现:
package com.dongnao.jack;
import java.util.ArrayList;
import java.util.List;
public class DNHashMap<K, V> implements DNMap<K, V> {
private static int defaultLength = 16;
private static double defaultLoader = 0.75;
private Entry<K, V>[] table = null;
private int size = 0;
public DNHashMap(int length, double loader) {
defaultLength = length;
defaultLoader = loader;
table = new Entry[defaultLength];
}
public DNHashMap() {
this(defaultLength, defaultLoader);
}
public V put(K k, V v) {
//在这里要判断一下,size是否达到了一个扩容的一个标准
if (size >= defaultLength * defaultLoader) {
up2size();
}
//1、 创建一个hash函数,根据key和hash函数算出数组下标
int index = getIndex(k);
Entry<K, V> entry = table[index];
if (entry == null) {
//如果entry为null,说明table的index位置上没有元素
table[index] = newEntry(k, v, null);
size++;
}
else {
//如果index位置不为空,说明index位置有元素,那么就要进行一个替换,然后next指针指向老数据
table[index] = newEntry(k, v, entry);
}
return table[index].getValue();
}
private void up2size() {
Entry<K, V>[] newTable = new Entry[2 * defaultLength];
//新创建数组以后,以前老数组里面的元素要对新数组进行再散列
againHash(newTable);
}
//新创建数组以后,以前老数组里面的元素要对新数组进行再散列
private void againHash(Entry<K, V>[] newTable) {
List<Entry<K, V>> list = new ArrayList<Entry<K, V>>();
for (int i = 0; i < table.length; i++) {
if (table[i] == null) {
continue;
}
findEntryByNext(table[i], list);
}
if (list.size() > 0) {
//要进行一个新数组的再散列
size = 0;
defaultLength = defaultLength * 2;
table = newTable;
for (Entry<K, V> entry : list) {
if (entry.next != null) {
entry.next = null;
}
put(entry.getKey(), entry.getValue());
}
}
}
private void findEntryByNext(Entry<K, V> entry, List<Entry<K, V>> list) {
if (entry != null && entry.next != null) {
list.add(entry);
findEntryByNext(entry.next, list);
}
else {
list.add(entry);
}
}
private Entry<K, V> newEntry(K k, V v, Entry<K, V> next) {
return new Entry(k, v, next);
}
private int getIndex(K k) {
int m = defaultLength;
int index = k.hashCode() % m;
return index >= 0 ? index : -index;
}
public V get(K k) {
//1、 创建一个hash函数,根据key和hash函数算出数组下标
int index = getIndex(k);
if (table[index] == null) {
return null;
}
return findValueByEqualKey(k, table[index]);
}
public V findValueByEqualKey(K k, Entry<K, V> entry) {
if (k == entry.getKey() || k.equals(entry.getKey())) {
return entry.getValue();
}
else {
if (entry.next != null) {
return findValueByEqualKey(k, entry.next);
}
}
return null;
}
public int size() {
return size;
}
class Entry<K, V> implements DNMap.Entry<K, V> {
K k;
V v;
Entry<K, V> next;
public Entry(K k, V v, Entry<K, V> next) {
this.k = k;
this.v = v;
this.next = next;
}
public K getKey() {
return k;
}
public V getValue() {
return v;
}
}
}
测试类:
package com.dongnao.jack;
public class Test {
public static void main(String[] args) {
DNMap<String, String> dnmap = new DNHashMap<String, String>();
Long t1 = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
dnmap.put("key" + i, "value" + i);
}
for (int i = 0; i < 10000; i++) {
System.out.println("key: " + "key" + i + " value:"
+ dnmap.get("key" + i));
}
Long t2 = System.currentTimeMillis();
// System.out.println("jack写的dnhashMap耗时:" + (t2 - t1));
// System.out.println("-----------------------HashMap--------------------------");
//
// Map<String, String> map = new HashMap<String, String>();
// Long t3 = System.currentTimeMillis();
// for (int i = 0; i < 1000; i++) {
// map.put("key" + i, "value" + i);
// }
//
// for (int i = 0; i < 1000; i++) {
// System.out.println("key: " + "key" + i + " value:"
// + map.get("key" + i));
// }
// Long t4 = System.currentTimeMillis();
// System.out.println("jdk的hashMap耗时:" + (t4 - t3));
}
}
参考资料:
HashMap原理和代码浅析:http://blog.csdn.net/u011060103/article/details/51355763