集合框架系列教材 (十六)- 其他 - Java HashCode原理详解

步骤1:List查找的低效率
步骤2:HashMap的性能表现
步骤3:HashMap原理与字典
步骤4:分析HashMap性能卓越的原因
步骤5:HashSet判断是否重复
步骤6:练习-自定义字符串的hashcode
步骤7:答案-自定义字符串的hashcode
步骤8:练习-自定义MyHashMap
步骤9:答案-自定义MyHashMap
步骤10:练习-内容查找性能比较
步骤11:答案-内容查找性能比较

步骤 1 : List查找的低效率

假设在List中存放着无重复名称,没有顺序的2000000个Hero
要把名字叫做“hero 1000000”的对象找出来
List的做法是对每一个进行挨个遍历,直到找到名字叫做“hero 1000000”的英雄。
最差的情况下,需要遍历和比较2000000次,才能找到对应的英雄。
测试逻辑:
1. 初始化2000000个对象到ArrayList中
2. 打乱容器中的数据顺序
3. 进行10次查询,统计每一次消耗的时间
不同计算机的配置情况下,所花的时间是有区别的。 在本机上,花掉的时间大概是600毫秒左右

List查找的低效率

package collection;

     

import java.util.ArrayList;

import java.util.Collections;

import java.util.List;

     

import charactor.Hero;

     

public class TestCollection {

    public static void main(String[] args) {

        List<Hero> heros = new ArrayList<Hero>();

            

        for (int j = 0; j < 2000000; j++) {

            Hero h = new Hero("Hero " + j);

            heros.add(h);

        }

            

        // 进行10次查找,观察大体的平均值

        for (int i = 0; i < 10; i++) {

            // 打乱heros中元素的顺序

            Collections.shuffle(heros);

             

            long start = System.currentTimeMillis();

     

            String target = "Hero 1000000";

     

            for (Hero hero : heros) {

                if (hero.name.equals(target)) {

                    System.out.println("找到了 hero!" );

                    break;

                }

            }

            long end = System.currentTimeMillis();

            long elapsed = end - start;

            System.out.println("一共花了:" + elapsed + " 毫秒");

        }

             

    }

}

步骤 2 : HashMap的性能表现

使用HashMap 做同样的查找
1. 初始化2000000个对象到HashMap中。
2. 进行10次查询
3. 统计每一次的查询消耗的时间
可以观察到,几乎不花时间,花费的时间在1毫秒以内

HashMap的性能表现

package collection;

  

import java.util.HashMap;

  

import charactor.Hero;

  

public class TestCollection {

    public static void main(String[] args) {

          

        HashMap<String,Hero> heroMap = new HashMap<String,Hero>();

        for (int j = 0; j < 2000000; j++) {

            Hero h = new Hero("Hero " + j);

            heroMap.put(h.name, h);

        }

        System.out.println("数据准备完成");

  

        for (int i = 0; i < 10; i++) {

            long start = System.currentTimeMillis();

              

            //查找名字是Hero 1000000的对象

            Hero target = heroMap.get("Hero 1000000");

            System.out.println("找到了 hero!" + target.name);

              

            long end = System.currentTimeMillis();

            long elapsed = end - start;

            System.out.println("一共花了:" + elapsed + " 毫秒");

        }

  

    }

}

步骤 3 : HashMap原理与字典

在展开HashMap原理的讲解之前,首先回忆一下大家初中和高中使用的汉英字典。

比如要找一个单词对应的中文意思,假设单词是Lengendary,首先在目录找到Lengendary在第 555页。 

然后,翻到第555页,这页不只一个单词,但是量已经很少了,逐一比较,很快就定位目标单词Lengendary。

555相当于就是Lengendary对应的hashcode

步骤 4 : 分析HashMap性能卓越的原因

-----hashcode概念-----
所有的对象,都有一个对应的hashcode(散列值)
比如字符串“gareen”对应的是1001 (实际上不是,这里是方便理解,假设的值)
比如字符串“temoo”对应的是1004
比如字符串“db”对应的是1008
比如字符串“annie”对应的是1008

-----保存数据-----
准备一个数组,其长度是2000,并且设定特殊的hashcode算法,使得所有字符串对应的hashcode,都会落在0-1999之间
要存放名字是"gareen"的英雄,就把该英雄和名称组成一个键值对,存放在数组的1001这个位置上
要存放名字是"temoo"的英雄,就把该英雄存放在数组的1004这个位置上
要存放名字是"db"的英雄,就把该英雄存放在数组的1008这个位置上
要存放名字是"annie"的英雄,然而 "annie"的hashcode 1008对应的位置已经有db英雄了,那么就在这里创建一个链表,接在db英雄后面存放annie

-----查找数据-----
比如要查找gareen,首先计算"gareen"的hashcode是1001,根据1001这个下标,到数组中进行定位,(根据数组下标进行定位,是非常快速的) 发现1001这个位置就只有一个英雄,那么该英雄就是gareen.
比如要查找annie,首先计算"annie"的hashcode是1008,根据1008这个下标,到数组中进行定位,发现1008这个位置有两个英雄,那么就对两个英雄的名字进行逐一比较(equals),因为此时需要比较的量就已经少很多了,很快也就可以找出目标英雄
这就是使用hashmap进行查询,非常快原理。


这是一种用空间换时间的思维方式

分析HashMap性能卓越的原因

步骤 5 : HashSet判断是否重复

HashSet的数据是不能重复的,相同数据不能保存在一起,到底如何判断是否是重复的呢?
根据HashSet和HashMap的关系,我们了解到因为HashSet没有自身的实现,而是里面封装了一个HashMap,所以本质上就是判断HashMap的key是否重复。

再通过上一步的学习,key是否重复,是由两个步骤判断的:
hashcode是否一样
如果hashcode不一样,就是在不同的坑里,一定是不重复的
如果hashcode一样,就是在同一个坑里,还需要进行equals比较
如果equals一样,则是重复数据
如果equals不一样,则是不同数据。


更多内容,点击了解: https://how2j.cn/k/collection/collection-hashcode/371.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值