核心原理
底层实现
- 底层采用哈希表,一种非常重要的数据结构,redis数据库的核心技术和HashMap一样
- 数据结构中数组加链表对数据进行存储时,各有特点:
- 数组占用空间连续。寻址容易,查询速度快,但是增加和删除效率非常低
- 链表占用空间不连续。寻址困难,查询速度慢,但是增删效率非常高
- 哈希表结合了数组和链表的优点,查询快,增删效率也高。其本质是“数组+链表”
- 一个Entry对象存储内容如下
- key 键对象 value 值对象
- next 下一个节点
- hash 键对象的hash值
- 每一个Entry对象就是一个单向链表结构,使用图形表示一个Entry对象的典示例
手写示例
package collection;
/**
* 自定义接口MyMap,实现Map部分内容
* @pram K,V
*/
public interface MyMap<K,V> {
int size();
boolean isEmpty();
boolean containsKey(Object key);
boolean containsValue(Object value);
V get(K key);
void put(K key, V value);
void remove(Object key);
}
package collection;
public class MyHashMap<K,V> implements MyMap<K,V>{
private final static int INIT_CAPACITY = 1<<4;
private int size;
private Entry[] table;
public MyHashMap() {
table = new Entry[INIT_CAPACITY];
}
public static void main(String[] args) {
MyHashMap<String,String> hm = new MyHashMap<>();
hm.put("name","zhangsan");
hm.put("age","13");
hm.put("sex","male");
hm.put("career","home");
hm.put("career","car");
System.out.println(hm.get("sex"));
System.out.println(hm.toString());
hm.remove("age");
System.out.println(hm.toString());
}
private int hash(K key) {
int hashVal = key.hashCode();
hashVal = (hashVal<0)?-hashVal:hashVal;
return hashVal & (table.length-1);
// return hashVal & (1);
}
@Override
public int size() {
return size;
}
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public boolean containsKey(Object key) {
return false;
}
@Override
public boolean containsValue(Object value) {
return false;
}
@Override
public V get(K key) {
int index = hash(key);
Entry e = table[index];
while (e != null){
if (e.key.equals(key)){
return (V)e.value;
}
e = e.next;
}
return null;
}
@Override
public void put(K key, V value) {
int index = hash(key);
Entry en = new Entry<>(index,key,value,null);
if (table[index] == null){
table[index] = en;
}else{
Entry pos = table[index];
Entry last = pos;
while (pos!=null) {
if (pos.key.equals(key)){
pos.value = value;
return;
}
last = pos;
pos= pos.next;
}
last.next = en;
}
size++;
return;
}
@Override
public void remove(K key) {
int index = hash(key);
Entry e = table[index];
Entry prevous = null;
while (e != null) {
if (e.key.equals(key)) {
if (prevous == null) {
// 说明是第0个元素
e = e.next;
} else {
// 说明是第n个元素
prevous.next = e.next;
}
size --;
return;
}
prevous = e;
e = e.next;
}
return;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[");
for (Entry entry:table) {
while(entry!=null){
sb.append("{"+entry.key + ":" + entry.value + "}");
if (entry.next!=null){
sb.append(",");
}
entry = entry.next;
}
}
sb.append("]");
return sb.toString();
}
}
class Entry<K,V>{
int hash;
K key;
V value;
Entry next;
public Entry(int hash, K key, V value, Entry next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
public Entry() {}
}
HashSet
package collection;
public class MyHashSet<E> {
MyHashMap map;
public static final Object DEFAULT_OBJ = new Object();
public MyHashSet() {
map = new MyHashMap<>();
}
public static void main(String[] args) {
MyHashSet<String> set = new MyHashSet();
set.add("aaa");
set.add("bbb");
set.add("aaa");
}
private void add(E val) {
map.put(val,DEFAULT_OBJ);
}
public int size() {
return map.size();
}
}
知识点
- equals和hashcode通常必须在一起重写
- equals为true,那么hashcode必须相等,这么处理就是为了在HashMap的存取中不会出现悖论,如果hashcode不一致,在hashmap中就无法定位到正确的entry去进行比较
int index = hash(key);