HashMap(jdk7)的手写实现

#两个类,扩容,散列皆有详细的注释

1.顶层接口CMap

package com.cn.map;
import java.io.Serializable;
import java.util.Set;

/**
 * 自定义map接口
 * @author Mc
 * @param <K>
 * @param <V>
 */
public interface CMap<K,V> extends Serializable,Cloneable {
	
	V put(K k,V v);
	V get(K k);
    
	/**
	 * 内部 Entry接口
	 * @param <K>
	 * @param <V>
	 */
	public abstract interface Entry<K,V>{
		
		public K getKey();
		public V getValue();
		
	}

    public Set<K> keySet();

}

2.hashmap实现类

package com.cn.map;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * map实现类
 * @author Mc
 */
public class CHashMap<K, V> implements CMap<K, V>{

	private static final  Integer DEFAULT_LENGTH = 1 << 4;//默认长度16
	private static  final Double DEFAULT_ADD_FACTORY = 0.75;//负载因子
	private static  final Integer MAX_LEGTH = 1 << 30;//map数组的最大容量
	private int useSize = 0; //槽点使用数量
	private Entry<K, V> table[];//内部数组
	private int size = DEFAULT_LENGTH;//当前容量
	/**
	 * 无参构造器
	 */
	public CHashMap(){
		initMap(DEFAULT_LENGTH);	
	}

	public CHashMap(int size){
		if(size <=0 )throw new IllegalArgumentException();
		initMap(size);	
	}

	/**
	 * 初始化 Map
	 * @param size  初始长度
	 * @param factory 负载因子
	 */
	private void initMap(int size) {
		this.size = size;
		this.table = new Entry[size];

	}

	/**
	 * 实现CMap接口中的抽象接口
	 * @param <K>
	 * @param <V>
	 */
	public class Entry<K, V> implements  CMap.Entry<K, V>{

		private V v;
		private K k;
		private Entry<K, V> next;

		public  Entry(K k,V v,Entry<K, V> next){
			this.v = v;
			this.k = k;
			this.next = next;

		}

		@Override
		public K getKey() {
			return this.k;
		}

		@Override
		public V getValue() {
			return this.v;
		}




	}

	@Override
	public V put(K k, V v) {
		if(k == null)putNullKey(k, v);
		//判断当前槽数是否需要扩容
		if(useSize > DEFAULT_ADD_FACTORY * size && size < MAX_LEGTH){
			//需要扩容
			System.out.println("------------------------hashMap is reSize-------------------------");
			up2size();
		}
		//获取该存放的数组索引位置
		int index = getIndex(k,table.length);
		//假设槽点没有值,则放置在链表头
		if(table[index] == null){
			table[index] = new Entry<K,V>(k, v, null);
			useSize ++;
			return null;
		}
		V oldValue = putValueToIndex(k,v,index);
		return oldValue;
	}


	/**
	 * 将kv放置在链表上
	 * @param k
	 * @param v
	 * @param index
	 * @return
	 */
	private V putValueToIndex(K k, V v, int index) {
		Entry<K,V> entry = table[index];
		//校验此链表上是否有重复
		for (Entry<K,V> e = entry; e != null; e = e.next) {
			if (e.k.equals(k) || e.k == k) {
				V oldValue = e.v;
				e.v = v;
				return oldValue;
			}
		}
		//无重复则占领链表头
		table[index] = new Entry<K,V>(k, v, entry);
		return null;
	}

	/**
	 * 计算索引
	 * @param k
	 * @param length
	 * @return
	 */
	private int getIndex(K k, int length) {
		int hashCode = k.hashCode();
		return hash(hashCode) & (length - 1);
	}

	/**
	 * 重算哈希值 此处是hashMap精髓中的精髓,皆为降低哈希碰撞
	 * @param hashCode
	 * @return
	 */
	private int hash(int hashCode) {
		//hash32
		hashCode = hashCode ^ ((hashCode >>> 20) ^ (hashCode >>> 12));
		return hashCode ^ ((hashCode >>> 7) ^ (hashCode >>> 4));
	}

	/**
	 * MAP扩容
	 */
	private void up2size() {
		Entry newTable[] = new Entry[size << 1];
		//将老数据全部重新HASH散列
		List<Entry<K,V>> list = new ArrayList<>();
		for(CHashMap<K, V>.Entry<K, V> entry : table){
			moveEntryToList(list,entry);
		}
		//正式扩容,重新散列
		size = size << 1;
		table = newTable;
		useSize = 0;//槽点归零
		for (Entry<K, V> entry : list) {
			put(entry.getKey(), entry.getValue());
		}
	}

	/**
	 * 将老table上的元素全部挪到list里面
	 * @param list
	 * @param entry 
	 */
	private void moveEntryToList(List<CHashMap<K, V>.Entry<K, V>> list, CHashMap<K, V>.Entry<K, V> entry) {
		if(entry == null)return;
		if(entry.next == null){
			list.add(entry);
		}else{
			//递归存入
			list.add(entry);
			moveEntryToList(list,entry.next);
		}

	}

	@Override
	public V get(K k) {
		if(k == null)return getNullKey();
		int index = getIndex(k, size);
		return findValueByIndex(k,table[index]);
	}

	/**
	 * 根据索引获取值
	 * @param k 
	 * @param entry
	 * @return
	 */
	private V findValueByIndex(K k, CHashMap<K, V>.Entry<K, V> entry) {
		if(entry == null)return null;
		if(entry.k.equals(k) || entry.k == k)return entry.v;
		//递归获取
		return findValueByIndex(k,entry.next);
	}

	/**
	 * 获取key为空的对象
	 * @return
	 */
	private V getNullKey(){
		Entry<K, V> entry = table[0];
		if(entry != null && entry.getKey() == null)return entry.v;
		return null;
	}

	/**
	 * 放置key为空的对象
	 * @return
	 */
	private V putNullKey(K k,V v){
		Entry<K, V> entry = table[0];
		if(entry == null){
			table[0] = new Entry<K, V>(k, v, null);
			return null;
		}
		if(entry.k == null){
			V oldValue = entry.v;
			entry.v = oldValue;
			return oldValue;
		}
		table[0] = new Entry<K, V>(k, v, entry);
		return null;
	}
	
	/**
	 * 获取key的集合
	 */
     public Set<K> keySet(){
    	 Set<K> set = new HashSet<>();
 		for(CHashMap<K, V>.Entry<K, V> entry : table){
 			moveEntryKeyToList(set,entry);
 		}
 		return set;
     }
     
     /**
 	 * 将table元素的key存入list
 	 * @param set
 	 * @param entry 
 	 */
 	private void moveEntryKeyToList(Set<K> set, CHashMap<K, V>.Entry<K, V> entry) {
 		if(entry == null)return;
 		if(entry.next == null){
 			set.add(entry.k);
 		}else{
 			//递归存入
 			set.add(entry.k);
 			moveEntryKeyToList(set,entry.next);
 		}

 	}
	
	
	/**
	 * 测试一波
	 * @param args
	 */
	public static void main(String[] args) {
		CMap<String,String> map = new CHashMap<>();
		for(int i = 0;i < 500 ;i++){
			map.put("key--" + i, "value--"+i);
		}
		
		System.out.println("=======================写死遍历=============================");
		for(int i = 0;i < 500 ;i++){
			System.out.println(map.get("key--" + i));
		}
		
		System.out.println("=======================keySet遍历=============================");
		for (String key : map.keySet()) {
			System.out.println(map.get(key) + "==>");
		}
		
	}

}
发布了9 篇原创文章 · 获赞 6 · 访问量 2782

猜你喜欢

转载自blog.csdn.net/qq_29145405/article/details/81843148