一、目的
自定义实现Java的散列表HashMap。
核心:
1、每个Java对象都有hashcode()方法返回哈希码。
2、把哈希码处理后,对一个数组容量取余数,获得存储下标。
3、如果多个元素的下标相同,把这些元素用链表存放在一起。
二、主要代码
(一)元素节点的抽象类Entry
java
/**
*
* @version 1.0.0
* <p>
* date: 2026/4/19
**/
public class Entry<K, V> {
// 键名
private K key;
// 值
private V value;
// 指向其他相同下标的元素
private Entry<K, V> next;
public Entry(K key, V value, Entry<K, V> next) {
this.key = key;
this.value = value;
this.next = next;
}
public K getKey() {
return key;
}
public void setKey(K key) {
this.key = key;
}
public V getValue() {
return value;
}
public void setValue(V value) {
this.value = value;
}
public Entry<K, V> getNext() {
return next;
}
public void setNext(Entry<K, V> next) {
this.next = next;
}
@Override
public String toString() {
return "Entry{" +
"key=" + key +
", value=" + value +
", next=" + next +
'}';
}
}
(二)KHashMap类
名字是KHashMap,和Java官方的HashMap区分。
java
/**
* @author
* @version 1.0.0
* <p>
* date: 2026/4/19
**/
public class KHashMap<K, V> {
private Object[] entries = null;
/**
* 元素总数
*/
private int size = 500;
/**
* 记录总数
*/
private int count = 0;
public KHashMap(){
this.entries = new Object[this.size];
}
public KHashMap(int size){
this.size = size;
this.entries = new Object[this.size];
}
/**
* 获得下标
* @param key
* @return
*/
private int getIndex(Object key){
int h = 0;
int code = 0;
if(key != null) {
h = key.hashCode() & 0x0FFFFFFF;
code = h ^ (h >>> 16);
}
return code % size;
}
/**
* 设置键
* @param key
* @param value
*/
public synchronized void put(K key, V value){
if(key == null){
throw new NullPointerException("key is null.");
}
// 获得下标
int index = getIndex(key);
Entry<K, V> o = (Entry<K, V>) entries[index];
// 如果下标存在元素:
if(o != null){
// 插入元素到链表
insert(o, key, value);
} else{
// 直接创建新元素
entries[index] = new Entry<K, V>(key, value, null);
count++;
}
}
/**
* 获取值
* @param key
* @return
*/
public synchronized V get(K key){
if(key == null){
throw new NullPointerException("key is null.");
}
// 获取下标
int k = getIndex(key);
// 去对应下标查询值:
Entry<K, V> o = (Entry<K, V>)entries[k];
// 如果存在元素:
if(o != null){
// 链表存在,查询链表返回。
return find(o, key);
}
return null;
}
/**
* 移除节点
* @param key
* @return
*/
public synchronized boolean remove(K key){
// 找到位置清除
if(key == null){
throw new NullPointerException("key is null.");
}
// 获得下标
int index = getIndex(key);
Entry<K, V> o = (Entry<K, V>)entries[index];
// 如果存在元素
if(o != null){
// 找到位置,清除元素链表
Entry<K, V> p = o;
Entry<K, V> pre = null;
while(p != null){
if(p.getKey().equals(key)){
break;
}
pre = p;
p = p.getNext();
}
// 如果不为空,代表找到元素了
if(p != null){
if(pre != null){
pre.setNext(p.getNext());
} else {
// 说明是第一个节点
entries[index] = p.getNext();
}
count--;
return true;
} else {
return false;
}
}
return false;
}
/**
* 从链表中设置元素
* @param p
* @param key
* @param value
*/
private synchronized void insert(Entry<K, V> p, K key, V value){
Entry<K, V> pre = null;
while(p != null){
// 键名相等就设置
if(p.getKey() != null && p.getKey().equals(key)){
p.setValue(value);
break;
}
// 记录上一个元素
pre = p;
p = p.getNext();
}
// 如果为空,代表是全部查了
if(p == null && pre != null){
// 添加到末尾
pre.setNext(new Entry<K, V>(key, value, null));
count++;
}
}
/**
* 从链表中查询元素
* @param p 链表
* @param key 键名
* @return
*/
private V find(Entry<K, V> p, Object key){
V v = null;
while(p != null){
if(p.getKey() != null && p.getKey().equals(key)){
v = p.getValue();
break;
}
p = p.getNext();
}
return v;
}
/**
* 获取元素个数
* @return
*/
public synchronized int size(){
return this.count;
}
/**
* 获得键的集合
* @return
*/
public synchronized Object[] keys(){
Object[] result = new Object[count];
int index = 0;
for(int k = 0; k < size; k++){
Entry<K, V> temp = (Entry<K, V>) entries[k];
while(temp != null){
if(index < result.length) {
result[index] = temp.getKey();
temp = temp.getNext();
index++;
}
}
}
return result;
}
/**
* 获取值的数组
* @return
*/
public synchronized Object[] values(){
Object[] result = new Object[count];
int index = 0;
for(int k = 0; k < size; k++){
Entry<K, V> temp = (Entry<K, V>) entries[k];
while(temp != null){
if(index < result.length){
result[index] = temp.getValue();
temp = temp.getNext();
index++;
}
}
}
return result;
}
/**
* 清空元素
*/
public synchronized void clear(){
// 重新指向新的对象数组
this.entries = new Object[this.size];
}
}
三、测试代码
1、代码
java
/**
* @author
* @version 1.0.0
* <p>
* date: 2026/4/22
**/
public class Test {
public static void main(String[] args) {
KHashMap<String, String> map = new KHashMap<String, String>();
map.put("nnn1", "小明");
map.put("nnn2", "小红");
map.put("nnn3", "小花");
System.out.println("nnn1:" + map.get("nnn1"));
System.out.println("nnn2:" + map.get("nnn2"));
System.out.println("nnn3:" + map.get("nnn3"));
System.out.println("个数:" + map.size());
System.out.println("键的集合:");
Object[] keys = map.keys();
for (int i = 0; i < keys.length; i++) {
System.out.println(keys[i]);
}
System.out.println("-----------");
System.out.println("值的集合:");
Object[] values = map.values();
for (int i = 0; i < values.length; i++) {
System.out.println(values[i]);
}
}
}
2、执行结果

四、总结
1、基本满足实现要求。
2、最复杂的是计算下标、操作链表的新增节点、删除节点、查找节点。