手写HashMap及HashCode简易版,快速深入理解其内部运行逻辑

定义接口类 IHasMap

public interface IHasMap {
    public void put(String key,Object object);
    public Object get(String key);
}

定义键值类 Entry

public class Entry {
    public Object key;
    public Object value;
    public Entry(Object key, Object value) {
        super();
        this.key = key;
        this.value = value;
    }
    @Override
    public String toString() {
        return "[key=" + key + ", value=" + value + "]";
    }
}

定义传入字符串返回对应1-2000的数字值 模拟hashcode类

/**
 * 自定义字符串的hashcode
 */
public class hashcode {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        //生成100个字符串 长度2-10不等
        for(int i=0;i<100;i++){
            list.add(Test06.captcha((int) (Math.random() * 8) + 2));
        }
        for (String s : list) {
            //System.out.println(s+"的自定义hashcode是:"+Myhashcode(s));
            System.out.printf("%-10s的自定义hashcode是:%d%n",s,Myhashcode(s));
        }

    }

    /**
     * 静态方法 返回一个字符串的hashcose
     */
    public static int Myhashcode(String string) {
        int hashcode = 0;
        if (0 != string.length()) {
            //(s[0]+ s[1] + s[2] + s[3]+ s[n-1])*23 自定义算法
            return add(string);
        } else {
            return hashcode;
        }
    }

    public static int add(String str) {
        int[] strsum = new int[str.length()];
        for(int i=0;i<str.length();i++){
            int i1 = str.charAt(i);
            strsum[i] = i1;
        }
        int sum = 0;
        for (int i : strsum) {
            sum += i;
        }
        sum = sum*23;

        if(sum<0){//如果是负取绝对值
            sum = Math.abs(sum);
        }
        if((sum>1999)){//超过1999取余
            sum = sum%2000;
        }

        return sum;

    }
}

创建MyHashMap类 模拟HashMap类 并做性能测试

/**
 * 根据前面学习的hashcode的原理和自定义hashcode, 设计一个MyHashMap,实现接口IHashMap
 *
 * MyHashMap内部由一个长度是2000的对象数组实现。
 *
 * 设计put(String key,Object value)方法
 * 首先通过上一个自定义字符串的hashcode练习获取到该字符串的hashcode,然后把这个hashcode作为下标,定位到数组的指定位置。
 * 如果该位置没有数据,则把字符串和对象组合成键值对Entry,再创建一个LinkedList,把键值对,放进LinkedList中,最后把LinkedList 保存在这个位置。
 * 如果该位置有数据,一定是一个LinkedList,则把字符串和对象组合成键值对Entry,插入到LinkedList后面。
 *
 * 设计 Object get(String key) 方法
 * 首先通过上一个自定义字符串的hashcode练习获取到该字符串的hashcode,然后把这个hashcode作为下标,定位到数组的指定位置。
 * 如果这个位置没有数据,则返回空
 * 如果这个位置有数据,则挨个比较其中键值对的键-字符串,是否equals,找到匹配的,把键值对的值,返回出去。找不到匹配的,就返回空
 */
public class MyHashMap implements IHasMap {
    public static void main(String[] args) {
        List<Hero> hs = new ArrayList<>();
        System.out.println("300万个对象初始化开始");
        for (int i=0;i<3000000;i++){
            Hero h = new Hero("hero"+random());//hero-5555
            hs.add(h);
        }
        //hero英雄属性name相同的对象放在同一个list集合中 name作为Key
        MyHashMap myHashMap = new MyHashMap();
        for (Hero h : hs){
            List<Hero> list = (List<Hero>) myHashMap.get(h.name);//找到这个集合对象 键值对的value
            if(list==null){
                list = new ArrayList<>();//
                myHashMap.put(h.name,list);//hero-5555
            }
            list.add(h);// name相同的英雄对象直接放到集合中
        }
        System.out.println("300万个对象初始化结束");
        System.out.println("开始查找");

        long s = System.currentTimeMillis();
        List<Hero> re = (List<Hero>) myHashMap.get("hero5555");
        long e = System.currentTimeMillis();
        System.out.println("MyHashMap名字是hero-5555的英雄有:" + re.size()+"个"+" 时间:"+(e-s)+"毫秒");
        //for循环
        s = System.currentTimeMillis();
        int count = 0;
        for (Hero h : hs) {
            if (h.name.equals("hero5555")){
                count++;
            }
        }
        e = System.currentTimeMillis();
        System.out.println("for名字是hero-5555的英雄有:" + count +"个"+" 时间:"+(e-s)+"毫秒");

    }

    public static int random(){
        return (int)((Math.random()*9000)+1000);
    }

    //MyHashMap内部由一个长度是2000的对象数组实现
    LinkedList<Entry>[] values = new LinkedList[2000];

    @Override
    public void put(String key, Object object) {
        //拿到hashcode
        int hashcodes = hashcode.Myhashcode(key);//获得该字符串的 hashcode 1-2000

        //找到对应的Linkedlist
        LinkedList<Entry> list = values[hashcodes];//找到链表数组下标为hashcode的链表对象

        //判断是否为空 如果空就创建一个实例 如果这个链表下面的对象为空(Entry - 键值对对象)
        if(null == list ){
            list = new LinkedList<>();//创建一个链表容器
            values[hashcodes] = list;//放到该链表数组对应的下标下边
        }

        //判断key是否有对应的键值对
        boolean found = false;
        for (Entry entry : list) {//如果该数组下标的链表对象不为空 就判断链表对象Entry的键KEY是否相等 如果相等就更新值Value
            // 如果已经有了 则替换
            if(key.equals(entry.key)){
                entry.value = object;
                found = true;
                break;
            }
        }

        //如果没有存在的键值对 则创建
        if(!found){// 如果该键key的对象不存在 就创建一个Entry键值对象
            Entry entry = new Entry(key,object);
            list.add(entry);//添加的对象中
        }
    }

    @Override
    public Object get(String key) {//根据键的字符串查询对应存放数组的位置 找到位置后查询匹配的Key然后返回
        // 获取hashcode
        int hashcodes = hashcode.Myhashcode(key);

        // 找到hashcode对应的linkedlist
        LinkedList<Entry> list = values[hashcodes];
        if(null == list){
            return null;
        }

        Object res = null;

        //挨个比较每个键值队的key 找到匹配的返回对象
        for(Entry entry : list) {
            if (entry.key.equals(key)) {
                res = entry.value;
                break;
            }
        }

        return res;
    }

    @Override
    public String toString() {
        LinkedList<Entry> res = new LinkedList<>();

        for (LinkedList<Entry> linkedList : values) {
            if(null == linkedList){
                continue;
            }else {
                res.addAll(linkedList);
            }
        }
        return res.toString();
    }
}

运行结果

300万个对象初始化开始
300万个对象初始化结束
开始查找
MyHashMap名字是hero-5555的英雄有:349个 时间:0毫秒
for名字是hero-5555的英雄有:349个 时间:33毫秒

https://how2j.cn?p=316556学习及视频讲解 how2j

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值