简单实现HashMap的核心方法

今天就简单了解一下HashMap的实现:
首先先了解一下hashMap:它的底层结构是哈希表,采用了顺序表+链表 ;同一个链表上的存储地址都是相同的是发生冲突的元素;
物理模型

每一个HashMap都包含了一个主数组,数组的每一个节点又包含了链表,每一个链表都是一个Entry对象 其中包含了,hash:使用key计算的哈希码,key:唯一的entry标识,value:对应的值,next:指向下一个节点的地址
同一个链表节点的哈希码不同,但是存储的地址是相同的;
相对于单链表和双链表,HashMap中的链表与之不同的是,HashMap中添加对象是添加在数组中的首个位置的,不是再后面添加了。
HashMap的优点:

  • 添加快,查询快,原因:他们都是通过计算得到存储位置的,并不是通过比较得到的,
    存储是无序的,
    key值是唯一的

HashMap默认空间是16 ,装填因子为75%,当HashMap存储到了160.75=12的时候,HashMap会扩容 扩容原来大小的2倍 即:162=32
分析HashMap put动作:put分为3部分,
1、计算哈希码值
根据key.hashCode();得到哈希码
2、计算存储位置
int index=hashCode%table.length;//根据哈希值来取余 得到存储的位置
3、存储数据到指定的位置
3.1、首先判断该存储位置是否有值 如果没有值的话 就new一个netry对象
table[index]=new Entry(key,value,null,hashCode);
同时size++;
3.2、如果有值,那么就需要查询相同的key是否存在,如果存在就覆盖之前相同key的值
创建entry并且指向链表的第一个对象
Entry entry = table[index];
循环entry对象,当entry对象的key等于要添加对象的key 同时 entry的hash值等于计算出来的hash值 表示该key存在
entry.value=value;
将新的value赋值给老的value
3.3、如果没有相同的key,添加一个新的节点 到链表的第一个位置
Entry firstEntry = table[index];
table[index] = new Entry(key,value,firstEntry,hashCode);
size++;
上代码:
Map接口

/**
 * 简单实现HashMap的核心方法
 */
public interface Map {

    public void put(Object key,Object value);

    public Object get(Object key);

    public  int size();

    public boolean isEmpty();

    //定义内部接口
    interface Entry {
        public Object getKey();

        public Object getValue();
    }

}

HashMap实现类

public class HashMap implements Map{

    static final int DEFAULT_INITIAL_CAPACITY = 16;//hashMap默认长度 超过75% 即16*0.75=12就扩容 扩容大小为2倍

    static final float DEFAULT_LOAD_FACTOR = 0.75f;//扩容因子

    transient int size;//链表中Entry对象的个数

    transient Entry[] table = null; //定义的主数组

    /**
     *  int capacity = 1;
     while (capacity < initialCapacity)
     capacity <<= 1;
     重点:如果指定的初始长度不是2的幂,则会转换成2的幂
     */
    public HashMap(){
        table=new Entry[DEFAULT_INITIAL_CAPACITY];//默认16
    }

    /**
     * 核心
     * @param key
     * @param value
     */
    @Override
    public void put(Object key, Object value) {
        //1、计算哈希码
            int hashCode=key.hashCode();//根据key来计算哈希值
        //2、计算存储位置
            int index=hashCode%table.length;//根据哈希值来取余 得到存储的位置  源码:h & (length-1); 效果一样,但是效率高
        //3、存储数据到指定的位置
        if(table[index]==null){//说明该存储位置还未存在数据
            table[index]=new Entry(key,value,null,hashCode);
                size++;
        }else{//该数据已经存在数据 查询是否有相同的key值存在
            Entry entry = table[index];//指向链表的第一个元素
            while (entry!=null){
              //开始比较
              if(entry.hash== hashCode && entry.getKey().equals(key)){ //当entry对象的key等于要添加对象的key 同时 entry的hash值等于计算出来的hash值 表示该key存在
                  //key值存在开始覆盖
                  entry.value=value;
                    return;
              }
                //指向下一个节点
                entry = entry.next;
            }
            //如果没有相同的key,添加一个新的节点 到链表的第一个位置
            Entry firstEntry = table[index];
            table[index] = new Entry(key,value,firstEntry,hashCode);
            size++;
        }
    }

    @Override
    public Object get(Object key) {
        //计算哈希值
        int hashCode=key.hashCode();
        //计算存储位置
        int index=hashCode%table.length;
        Entry e=null;
        if(table[index]!=null){//该位置存储的有元素
            Entry entry=table[index];//指向链表的第一个元素
            while (entry!=null){
                //比较
                if(entry.hash== hashCode && entry.getKey().equals(key)){//找到了
                    e = entry;
                    break;
                }
                //指向下一个节点
                entry = entry.next;
            }


        }

        return e==null?null:e.getValue();
    }

    public String toString(){
        StringBuilder builder=new StringBuilder("{");
        for (int i=0;i<table.length;i++){
            //循环主数组
            if(table[i] != null ) {
                Entry entry = table[i];//指向链表第一个元素
                while (entry!= null) {
                    builder.append(entry.key + "=" + entry.value + ",");
                    //指向下一个节点
                    entry = entry.next;
                }
            }

        }
        if(size != 0){
            builder.deleteCharAt(builder.length()-1);
        }
        builder.append("}");
        return builder.toString();
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return size==0;
    }

    //定义encty对象 每一个主数组中的链表元素都是一个encrt对象
    class Entry implements Map.Entry{
        final Object key; //Entry对象的key
        Object value;//Entry对象的value
        Entry next; //指向的下一个Entry对象
        int hash;//计算的哈希码值

        public Entry(Object key,Object value,Entry next,int hash){
            this.key=key;
            this.value=value;
            this.hash=hash;
            this.next=next;

        }

        @Override
        public Object getKey() {
            return key;
        }

        @Override
        public Object getValue() {
            return value;
        }

        @Override
        public String toString() {
            return "Entry{" +
                    "key=" + key +
                    ", value=" + value +
                    ", next=" + next +
                    ", hash=" + hash +
                    '}';
        }
    }

}

测试类

public class TestHashMap {
    public static void main(String[] args) {
        HashMap map = new HashMap();
        map.put(23,"Italian");
        map.put(47,"England");
        map.put(23,"China");
        map.put(36,"Japan");
        map.put(48,"America");
        map.put(86,"the United States");
        map.put(67,"France");
        System.out.println(map.size());
        System.out.println(map.get(23));//Entry ---China
        System.out.println(map.toString());

    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值