Java集合相关学习——手写一个简单的Map接口实现类(HashMap)
Posted 张起灵-小哥
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java集合相关学习——手写一个简单的Map接口实现类(HashMap)相关的知识,希望对你有一定的参考价值。
1.关于Map和HashMap
这两个东西想必大家都很熟悉了,简单的概括就是:面试中会问到、笔试中会考到、开发中会用到。
那么有关这块知识呢,大家可以参考我的这几篇文章:
2.案例代码
要求是这样的:
请完善TestMap类,要求只实现get、put、remove、size四个方法
- 要求不能使用第三方包,不能使用JDK中Map实现类
- 请对完成的方法进行测试,在main方法中调用验证
因为在Map这种K-V键值对的存储结构中,其实也是一个哈希表,那么它每个节点都有自己的 key、value、hash值、指向下一个节点的指针,所以我们也需要定义一个内部类来存储这些信息。
然后我们同时需要模仿jdk官方的Map接口,自定义我们自己的Map接口,其中包括一些常用方法。(具体的已经写在代码注释中了)
public interface Map<K, V>
int size();
boolean isEmpty();
boolean containsKey(Object key);
boolean containsValue(Object value);
V get(Object key);
V put(K key, V value);
V remove(Object key);
void clear();
interface Entry<K, V>
K getKey();
V getValue();
import java.util.Collection;
import java.util.Set;
public class TestMap<K, V> implements Map<K, V>
private static final int DEFAULT_INITIAL_CAPACITY = 16;
private static final float DEFAULT_LOAD_FACTOR = 0.75f;
private float loadFactor = 0;
private int initCapacity = 0;
private Entry<K, V>[] table = null;
private int size = 0;
public TestMap()
this.loadFactor = DEFAULT_LOAD_FACTOR;
this.initCapacity = DEFAULT_INITIAL_CAPACITY;
table = new Entry[this.initCapacity];
// private int hash(K key)
// int h;
// return (key == null) ? 0 : Math.abs((h = key.hashCode())) ^ (h >>> 16);
//
@Override
public int size()
return size;
@Override
public V get(Object key)
Entry<K, V> e = null; //默认不存在
//计算哈希码
int hash = key.hashCode();
//计算存储的位置
int index = hash % table.length;
//存储到指定的位置
if (table[index] != null) //该位置存储了元素
Entry<K, V> entry = table[index]; //先指向第一个元素
while (entry != null)
//比较
if (entry.hash == hash && entry.getKey().equals(key)) //找到了这个key
e = entry;
break;
//指向下一个结点,继续循环判断
entry = entry.next;
return e == null ? null : e.value;
@Override
public V put(K key, V value)
//计算哈希码
int hash = key.hashCode();
//计算存储的位置
int index = hash % table.length;
//存储到指定的位置
if (table[index] == null)
//该位置还没有元素
table[index] = new Entry<K, V>(key, value, null, hash);
++size;
else //该位置已经存储了元素
//查询是否存在相同key的Entry
Entry<K, V> entry = table[index]; //指向链表的第一个元素
while (entry != null)
//比较
if (entry.hash == hash && entry.getKey().equals(key))
//如果找到了相同的key,使用新的value将旧的value替换掉
entry.value = value;
return entry.value;
//指向下一个结点,继续循环判断
entry = entry.next;
//如果没有相同的key,添加新的结点,下一个结点就是原来的第一个结点,也就是table[index],添加到链表的第一个位置(table[index])
table[index] = new Entry<K, V>(key, value, table[index], hash);
++size;
return value;
@Override
public V remove(Object key)
//计算哈希码
int hash = key.hashCode();
//计算存储的位置
int index = hash % table.length;
//先定义一个prev表示待删除的元素的上一个
Entry<K, V> prev = table[index];
Entry<K, V> e = prev;
while (e != null)
//定位出e的下一个元素,当找到我们要删除的元素时,将链表切断,将prev和next连接即可。
Entry<K, V> next = e.next;
//在链表上定位到这个元素,先判断hash值是否相等,再判断key的equals是否相等!
if(e.hash == hash && (e.key == key || (key != null && key.equals(e.key))))
--size;
//这里,还得判断一个东西,即定位到的这个Entry是否是table[i],因为table[i]上的删除和链表上的删除有区别
if(prev == e)
table[index] = next;
else
prev.next = next; //如果不是table位置的,则是链表后边的元素,此时,将prev的下一个置为e的next即可,此时,e已被切断,e的前后Entry被连接起来
return e.value;
//上边的if没进去,则执行下一次循环,指针向后移动一位!
prev = e;
e = next;
return null;
@Override
public boolean isEmpty()
return size == 0;
@Override
public boolean containsKey(Object key)
return get(key) != null;
@Override
public boolean containsValue(Object value)
Entry<K, V>[] tab; V v;
if ((tab = table) != null && size > 0)
for (Entry<K, V> e : tab)
for (; e != null; e = e.next)
if ((v = e.value) == value ||
(value != null && value.equals(v)))
return true;
return false;
@Override
public void clear()
Entry<K, V>[] tab;
if ((tab = table) != null && size > 0)
size = 0;
for (int i = 0; i < tab.length; ++i)
tab[i] = null;
@Override
public String toString()
StringBuilder sb = new StringBuilder("");
for (int i = 0; i < table.length; i++) //外层循环主数组
if (table[i] != null)
Entry<K, V> entry = table[i]; //让entry指向链表的第一个元素
while (entry != null) //内层循环循环链表
sb.append(entry.key + " = " + entry.value + ", ");
//指向下一个结点,继续循环判断
entry = entry.next;
if (size != 0) //如果有元素就把最后一个逗号去掉
sb.deleteCharAt(sb.length() - 1);
sb.setCharAt(sb.length() - 1, '');
return sb.toString();
// HashMap中存储节点信息的数据结构
class Entry<K, V> implements Map.Entry<K, V>
K key;
V value;
Entry<K, V> next;
int hash; //记录下标
Entry(K key, V val, Entry<K, V> next, int hash)
this.key = key;
this.value = val;
this.next = next;
this.hash = hash;
@Override
public K getKey()
return key;
@Override
public V getValue()
return value;
public static void main(String[] args)
TestMap<String, Object> map = new TestMap<>();
map.put("姓名", "张三");
map.put("年龄", "20");
map.put("性别", "男");
map.put("爱好", "打篮球");
System.out.println(map.get("姓名"));
System.out.println(map);
System.out.println("map集合中键值对数量为:" + map.size());
System.out.println("map集合中是否包含key:" + map.containsKey("姓名"));
System.out.println("map集合中是否包含value:" + map.containsValue("小哥"));
String s = (String) map.remove("性别");
System.out.println("移除的key对应的value值为:" + s);
System.out.println("移除之后map集合中键值对数量为:" + map.size());
map.clear();
System.out.println("map集合是否为空:" + map.isEmpty());
以上是关于Java集合相关学习——手写一个简单的Map接口实现类(HashMap)的主要内容,如果未能解决你的问题,请参考以下文章
我在写一个java泛型接口实现时为啥报出double为意外的类型啊?源程序如下!
JAVA 开发升讯威在线客服系统:调用百度翻译接口实现实时自动翻译
JAVA 开发升讯威在线客服系统:调用百度翻译接口实现实时自动翻译