Java手写一个简单的HashMap

1.背景介绍

HashMap在Java中是常用的数据结构之一。HashMap 是一个散列表,它存储的内容是键值对(key-value)映射,并具有很快的访问速度。在JDK1.7中,HashMap是基于“数组+链表”实现的,而在JDK1.8以后,HashMap在底层实现中加入了红黑树用于提升查找速率。


图源网络,侵删

在JDK1.8中,当链表的长度大于阈值8时,这时这个链表将会转化成红黑树以提升查找效率。为什么阈值是8呢?请读者不妨思考一下这个问题,在文章末尾笔者将给出原因。(提示:想一想在红黑树和链表中查找一个元素的复杂度)

好了,关于HashMap就简单介绍到这里,接下来我们关注于自己实现一个HashMap—MyHashMap。

2.目标

在本次实现中,我们的目标如下:

  • 实现put(k, v),该方法返回V类型的元素,这里返回为空即可。
  • 实现get(k),该方法返回这个建对应的值v。
  • 实现remove(k),该方法将这个键对应的键值对删除,并返回对应的值v,如果不存在对应的键,返回空。
  • 实现size(),该方法返回HashMap中的键值对数目。

明确我们的目标后,就可以关注于具体实现了。

3.手写HashMap
3.1定义MyMap接口

这个接口定义了我们需要实现的具体行为。

public interface MyMap <K, V>{
   
    V get(K k);

    V put(K k, V v);

    int size();

    V remove(K k);

    boolean isEmpty();
}

接下来我们要根据这个接口的定义完成我们的MyHashMap类去实现接口中定义的行为。

3.2定义链表节点

因为HashMap中存在着链表,所以我们也需要实现一个链表。我们以内部类的形式定义这样一个节点Entry,Entry类保存了"K-V"数据,next字段表明它可能会是一个链表节点。

参考形式如下:

public class MyHashMap <K,V> implements MyMap<K, V> {
   
    //定义内部类Entry作为链表节点
     class Entry<K, V>{
   
         K k;
         V v;
         Entry<K,V> next;

         public Entry(K k, V v){
   
             this.k = k;
             this.v = v;
         }
     }
}

3.2定义成员变量

这里参照HashMap设置一个默认的容量capacity和默认的加载因子loadFactor,table就是底层数组,另外,考虑到size方法的实现,这里肯定还需要一个成员变量size用于表示HashMap的大小。

//定义成员变量
final static int DEFAULT_CAPACITY = 16;
final static float DEFAULT_LOAD_FACTOR = 0.75f;

private int capacity;
private float loadFactor;
private 
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,下面是一个简单手写HashMap实现,仅供参考: ```java public class MyHashMap<K, V> { private static final int DEFAULT_CAPACITY = 16; // 默认容量为16 private static final float DEFAULT_LOAD_FACTOR = 0.75f; // 默认负载因子为0.75 private int size; // 元素个数 private int threshold; // 阈值,当size >= threshold时,需要进行扩容 private float loadFactor; // 负载因子 private Node<K, V>[] table; // 存储元素的数组 public MyHashMap() { this(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR); } public MyHashMap(int initialCapacity) { this(initialCapacity, DEFAULT_LOAD_FACTOR); } public MyHashMap(int initialCapacity, float loadFactor) { if (initialCapacity <= 0) { throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity); } if (loadFactor <= 0 || Float.isNaN(loadFactor)) { throw new IllegalArgumentException("Illegal load factor: " + loadFactor); } this.loadFactor = loadFactor; this.table = new Node[initialCapacity]; this.threshold = (int) (initialCapacity * loadFactor); } public V put(K key, V value) { if (key == null) { return putForNullKey(value); } int hash = hash(key.hashCode()); int index = indexFor(hash, table.length); for (Node<K, V> node = table[index]; node != null; node = node.next) { if (node.hash == hash && (key == node.key || key.equals(node.key))) { V oldValue = node.value; node.value = value; return oldValue; } } addEntry(hash, key, value, index); return null; } private V putForNullKey(V value) { for (Node<K, V> node = table[0]; node != null; node = node.next) { if (node.key == null) { V oldValue = node.value; node.value = value; return oldValue; } } addEntry(0, null, value, 0); return null; } private void addEntry(int hash, K key, V value, int index) { Node<K, V> node = table[index]; table[index] = new Node(hash, key, value, node); if (++size >= threshold) { resize(); } } private void resize() { int oldCapacity = table.length; int newCapacity = oldCapacity * 2; Node<K, V>[] newTable = new Node[newCapacity]; for (Node<K, V> node : table) { while (node != null) { int index = indexFor(node.hash, newCapacity); Node<K, V> next = node.next; node.next = newTable[index]; newTable[index] = node; node = next; } } table = newTable; threshold = (int) (newCapacity * loadFactor); } public V get(K key) { if (key == null) { return getForNullKey(); } int hash = hash(key.hashCode()); int index = indexFor(hash, table.length); for (Node<K, V> node = table[index]; node != null; node = node.next) { if (node.hash == hash && (key == node.key || key.equals(node.key))) { return node.value; } } return null; } private V getForNullKey() { for (Node<K, V> node = table[0]; node != null; node = node.next) { if (node.key == null) { return node.value; } } return null; } public boolean containsKey(K key) { return get(key) != null; } public boolean isEmpty() { return size == 0; } public int size() { return size; } private int hash(int h) { h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); } private int indexFor(int hash, int length) { return hash & (length - 1); } private static class Node<K, V> { private final int hash; private final K key; private V value; private Node<K, V> next; public Node(int hash, K key, V value, Node<K, V> next) { this.hash = hash; this.key = key; this.value = value; this.next = next; } } } ``` 以上是一个简单HashMap实现,其中采用了链表法解决哈希冲突,并且在元素个数达到阈值时进行了扩容。需要注意的是,这个实现并不完整,仅作为参考。在实际使用中,还需要考虑并发性、迭代器等因素。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值