java自定义HashMap

本文探讨了如何基于自定义的MyArrayList和MyLinkedList实现Java中的HashMap。详细讲解了put、get、clear、containsKey、replace、remove等关键操作,并指出在确定数组下标时,虽然采用的是简单的hashcode取余运算,而未使用更高效的位运算方式(key.hash & (array.length-1))。文章还提及自定义HashMap不支持null值的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

HashMap的数据结构是数组+链表,之前的博客中有自定义的数组列表和链表,这里的数组和链表就是使用之前自定义的数组列表和链表。

实现的方法有put(K k,V v),get(K k),clear(),containsKey(K k),replace(K k,V v),remove(K k),不支持null值。

确定数组下标的方式直接用key的hashcode和数组容量进行取余运算,没有使用key.hash & (array.length-1)这种方式,道理一样,但后者效率比前者高一些。

下面是代码:

MyArrayList和MyLinkedList的实现参考之前的博客。

public class MyHashMap<K,V> {
	//实际存储的key-value键值对的个数
	public transient  int size;
	//当前数组容量
	private int arrayCapacity;
	//扩容判断的负载因子
	private  float loadFactor=0.75f;
	//扩容的阈值
	private int threshold;
	private MyArrayList<MyLinkedList<NodeEntry>> arrayList;
	
	private class NodeEntry{
		public K key;
		public V value;
		
		public NodeEntry(K key, V value) {
			super();
			this.key = key;
			this.value = value;
		}
		/**
		 * 重写hashCode和equals
		 */
		@Override
		public int hashCode() {
			// TODO Auto-generated method stub
			return this.key.hashCode();
		}
		@Override
		public boolean equals(Object obj) {
			if(!(obj instanceof MyHashMap.NodeEntry)){
				return false;
			}
			NodeEntry entry=(NodeEntry) obj;
			return this.key.equals(entry.key)&&this.value.equals(entry.value);
		}

		@Override
		public String toString() {
			return "NodeEntry [key=" + key + ", value=" + value + "]";
		}
	}
	
	//两个构造方法
	
	public MyHashMap() {
		this.arrayList=new MyArrayList<MyLinkedList<NodeEntry>>();
		this.arrayCapacity=arrayList.currentCapacity;
		this.threshold=(int) (arrayCapacity*loadFactor);
	}
	
	public MyHashMap(int capacity,float loadFactor) {
		this.arrayList=new MyArrayList<MyLinkedList<NodeEntry>>(capacity);
		this.arrayCapacity=arrayList.currentCapacity;
		this.loadFactor=loadFactor;
		this.threshold=(int) (arrayCapacity*loadFactor);
	}
	
	/**
	 * 存储数据,如果key已经存在,则新value覆盖旧value,并返回旧value
	 * @param k key
	 * @param v value
	 * @return
	 */
	public V put(K k,V v){
		if(k==null){
			throw new IllegalArgumentException("key不能为null");
		}
		if(containsKey(k)){
			return replace(k, v);
		}
		MyLinkedList<NodeEntry> linkedList;
		arrayCapacity=arrayList.currentCapacity;
		int i=k.hashCode()%arrayCapacity;
		linkedList=arrayList.get(i);
		if(linkedList==null){
			linkedList=new MyLinkedList<NodeEntry>();
		}
		linkedList.addNode(new NodeEntry(k, v));
		addNodeEntry(i, linkedList);
		size++;
		return null;
	}
	
	/**
	 * 根据key获取元素
	 * @param k
	 * @return
	 */
	public V get(K k){
		int i=k.hashCode()%this.arrayCapacity;
		MyLinkedList<NodeEntry> linkedList=this.arrayList.get(i);
		if(linkedList!=null){
			for (NodeEntry entry : linkedList) {
				if(entry.key==k||k.equals(entry.key)){
					return entry.value;
				}
			}
		}
		return null;
	}
	
	private void addNodeEntry(int index,MyLinkedList<NodeEntry> linkedList){
		if(size>=threshold&&this.arrayList.get(index)!=null){
			resizeArrayCapacity(this.arrayCapacity*2);
		}
		this.arrayList.set(index, linkedList);
		this.arrayList.size++;
	}
	
	/**
	 * 数组进行扩容,并将旧数组中的元素重新放到新数组中
	 * @param newCapacity 新数组的容量
	 */
	void resizeArrayCapacity(int newCapacity){
		//根据容量创建一个新数组
		MyArrayList<MyLinkedList<NodeEntry>> newlist=new MyArrayList<MyLinkedList<NodeEntry>>(newCapacity);
		MyLinkedList<NodeEntry> tempLinkedList = null;
		//遍历每一个链表的节点,获取新的数组下标,并将节点存放到新数组中去
		for (int i = 0; i < arrayList.currentCapacity; i++) {
			MyLinkedList<NodeEntry> nodeList=arrayList.get(i);
			if (nodeList!=null) {
				//System.err.println(nodeList.size);
				for (NodeEntry nodeEntry : nodeList) {
					//System.err.println(nodeEntry.key);
					int index=nodeEntry.key.hashCode()%newCapacity;
					//根据生成的数组下标,获取链表,如不存在则生成新的
					tempLinkedList=newlist.get(index);
					if(tempLinkedList==null){
						tempLinkedList=new MyLinkedList<NodeEntry>();
					}
					//链表中添加元素
					tempLinkedList.addNode(nodeEntry);
					//链表添加到新的list中
					newlist.set(index, tempLinkedList);
				}
				
			}
			
		}

		this.arrayList=newlist;
		this.arrayCapacity=newCapacity;
		this.threshold=(int) (arrayCapacity*loadFactor);
		
	}
	
	/**
	 * 清空map
	 */
	public void clear(){
		arrayList.clear();
		size=0;
		
	}
	


	
	/**
	 * 判断map是否存在该key
	 * @param k
	 * @return
	 */
    public boolean containsKey(K k) {
    	int i=k.hashCode()%this.arrayCapacity;
    	MyLinkedList<NodeEntry> linkedList=this.arrayList.get(i);
    	if(linkedList!=null){
			for (NodeEntry entry : linkedList) {
				if(entry.key==k||k.equals(entry.key)){
					return true;
					
				}
			}
    	}
    	
    	return false;
    }
    /**
     * 根据key和value替换元素
     * @param k
     * @param v
     * @return
     */
    public V replace(K k,V v){
    	int i=k.hashCode()%this.arrayCapacity;
    	MyLinkedList<NodeEntry> linkedList=this.arrayList.get(i);
    	V oldValue=null;
    	if(linkedList!=null){
			for (NodeEntry entry : linkedList) {
				if(entry.key==k||k.equals(entry.key)){
					oldValue=entry.value;
					entry.value=v;
					return oldValue;
					
				}
			}
    	}
    	
    	return oldValue;
    }
    /**
     * 根据key删除元素
     * @param k
     * @return
     */
    public V remove(K k){
    	V oldValue=null;
    	if(containsKey(k)){
    		oldValue=get(k);
        	int i=k.hashCode()%arrayCapacity;
        	MyLinkedList<NodeEntry> linkedList=arrayList.get(i);
        	if(linkedList!=null){
            		NodeEntry entry=new NodeEntry(k, oldValue);
            		try {
						linkedList.deleteNode(entry);
					} catch (Exception e) {
						e.printStackTrace();
					}
        	}
    	}
    	return oldValue;
    }
	
	
	public static void main(String[] args){
		MyHashMap<String, Object> map=new MyHashMap<String, Object>();
		
		map.put("name", "张三");
		map.put("age", "11");
		map.put("add", "北京");
		map.remove("age");
		map.remove("name");
		map.put("age", "655");
		System.err.println(map.get("age"));
		System.err.println(map.get("name"));
		//System.err.println(map.containsKey("990"));
	  }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值