00:01
行了同学们,那咱们这个呃,接着来啊接着来,我们上午呢,最主要是把这个这个接口当中常用的方法啊,大家要掌握啊,就比如说我们怎么去往集合里边添加元素啊,啊对吧,怎么去查找它的元素啊,包括怎么去迭代,那么包括便利这块呢,咱们也说了两种方式,各位啊,第一种方式呢,就是采用我们所说的一个迭代器的这种方式是吧?哎,迭代器呢,怎么办呀?哎,把这个map集合当中的K全部获取到是不是,然后对K进行过程当中啊,我们取出每一个K,通过K来干什么呀?去获取这个value是不是。是我们把直接把这个map集合转换成什么一个set集合,是不是,哎,这个map集合转成set集合呢?调哪个方法叫entry set是不是entry啊ENT set。拿到之后呢,我们可以拿到这个,可以对这个set集合进行遍历,每遍利一次,拿出其中一个node节点,然后呢,调用这个node节点的get方法,Get key get value来获取它的k value。
01:07
那么这两种方式呢,呃,是非常重要的啊,非常重要的。嗯,我再把这个再打开吧,这个map test01和TEST02,这是我们今天上午非常重要的一个内容啊,嗯,这个是说的我们map当中的常用方法,对吧?放元素啊,或者是存储元素,然后这个呢,是通过K来获取value,这个是清空的,判断包含某个K,判断包含某个value是否为空是吧?通过K来删除我们的键值,对啊,然后这个size呢,是获取我们集合的一个。哎,获取我们集合的这种元素的个数啊,键的个数value是拿到所有的value t呢,它是用来干什么呀?是用来获取我们所有键的,对不对?哎,然后呢,这个就是一种便利方式,拿到它之后,便利它通过其中这个key来获取这个value啊,然后下边这个方法entry set呢,这个方法是用来把map集合转换成set集合的,只不过这个set集合当中每个元素是一个entry。
02:07
然后我们对这个entry对象进行遍利,每变一次,我们调这个entry,它的方法是不是在第二个里面解释了,就是entry,它就是个node吧,是不是,哎调get key啊,Get value,说这种方式比较适合大数据量,对不对啊,因为上面的这种方式它是拿到key之后呢,通过key还得再去那个哈希表里边找什么。那个Y6吧,这个实际上就是有了这个对象之后,我们直接调用get k get value就可以拿到了,所以这个呢,是个大数据量便利啊,大数据量便利,当然这两种方式都行吧,你愿意使用哪种方式都可以啊,我们今天上午除了讲这两个东西之外啊,我们还讲了一个数据结构,对不对,那这个数据结构叫什么呢?叫做哎。哈西,呃,哈希表或者散列表的这种数据结构对不对?哎,哈希表或者散列表数据结构,那么这个数据结构呢,咱们在这里画了一个图啊,在哪儿呢?来打开这个,打开这个啊,打开这个啊打开这个,然后呢,课堂画图吧,应该是在这儿啊。
03:06
嗯,3月10号map转成,诶这个I表和散那表数据结构。那么行表散列表这个数据结构是这样,各位啊,这是一个一维数组,这个一维数组当中每个元素是个单向链表啊,这个单向链表,然后呢,数组当中每一个地方都有下标,012345对吧?大家重点掌握呢,往这个map集合里面存放元素k value的时候啊,它是怎么存放的,大家能把这个存储的这个过程呢给它说出来,是不是它会先去调用K的哈库的方法得出哈希值,是不是哈值经过一个哈算法转换成什么呀?数组下标。是不是啊,转正速度下标,那么今天上午我没有给大家提这个哈希碰撞的事儿,各位啊,今天中午的时候,你看有同学在微信里面发了说老师我测试了一下这个链表上,我这个这个节点的哈希和这个节点的哈希可以不一样,呃,这个如果,嗯,如果这么说的话,其实也不能也也也也不能说这个同学说的这个有问题啊,其实我在讲课的时候啊,在讲这个哈算法的时候,给大家说了一下,就这个哈算法,大家先不用先去研究这个东西啊。
04:10
就你在同一个链表上,你的哈希值是可以不同,但最后你转换成的数组下标肯定是同一个,当你哈希值如果不同,经过哈希算法转换成同一个数加与同,这怎么可能呢?这怎么可能呢?有这个可能。有这个可能啊,因为哈希算法底层它是怎么着啊,采用这个取取余或者叫求模的方式啊,我在微信群里发了,比如七对三求余数。对吧,得出的是一,那这个一就是什么呀?就是下标喽,那如果你的含义值是四对吧,四对三,求余数。它也等于几啊,也等于一,那这个一它是什么呀?数组下标喽,那你这个哈希值是七,这个哈希值是四,两个哈希值不一样对不对?哎,两个哈希值不同,最后导致的数组下标是一样的。那么像这种情况下,实际上我们在专业术语上叫哈希碰撞的事啊,哈希碰撞的事儿,但是有一件事大家注意啊,如果哈希值一样,那肯定在一个链表上是没问题的,就这个结论是肯定是没问题的啊,就是哈希值。
05:11
相同的话啊,一定是在同一个表上。因为哈希值相同,经过哈希算法转换的那个数字下边肯定是一样的。啊,就哈希碰撞的事,咱就没有提。但是我觉得这个不影响各位啊,不影响我们对这个哈希麦机的一个使用。不影响哈map机的使用啊呃,看情况吧,大家如果想研究的更深入一些,更透彻一些,你可以把这个底层源代码一行一行去读一读。啊。呃,哈吉只会一样吗?会呀,你像我这个不就一样吗?对吧,你看我这个new一个student,这不new一个student吗?这里面叫张三,这是张三啊,我在重启high的方法的时候,它一样啊。那你要不重写它肯定是不一样,你不重写你new了两个对象啊,你new了两个对象,两个内存地址,两个内存地址调high扣的方法肯定知识不一样的。
06:03
对吧,所以我们才要重写嘛,对不对,重写这个哈扣的方法。啊,重写这个海口的方法。就是说我们在上午最后这个哈希map t02这个例子里边,我们怎么说的各位啊。我们在这儿是不是最初的时候调equals方法,它的结果是false,然后重写equals是true,然后S1S2是不是往。是不是,呃,重启之后是处处表示S1和S2是同一个相同的对象啊,那相同对象他按理说应该不能存到行业set集合里边,对吧。结果我存进去存了没有啊,两个都存进去了是不是,它的长度是几啊?是二吧,它的长度是二,为什么长度是二呢?因为是你扭了两次,你没有重现哈希扣的方法,内存地址不一样,哈希值不同,碰巧了你这个没有碰撞,明白吧,这个碰巧你没碰撞啊,就这个值和这个值经过哈希算法转化的数组下标,它并没有碰撞。没有产生哈气碰撞。啊,咱也别提什么哈气碰撞了,别搞那么复杂啊,别搞那么复杂就是说。
07:04
我们现在转的数度下边不一样,所以这两个都放进去了,你的S方法虽然返回的是true,但是最后你还是放进去了,那我们ES方法返回true的话,是不是应该放一个就就对了,对吧,应该是一,所以在这里呢,我们重写e Co的时候,哎,你要注意哈code你也需要重写,如果你的哈code不去重写呢,那你调的这个行code一定是object里面行code方法得出的值肯定是含义值是不一样的。I值不一样的话,你就有可能导致这个数据都加进去了。相同的数据加进去,那就不就违背这个塞集合的存储原理了吗?无序不可重复,不可重复还是重复了呀,对吧,所以说在这里我给大家一个结论,什么结论就是放在我们哈希map机和K部分的元素。是不是,哎,或者说放在哈西塞的集合中的元素都需要重写哈的方法和ES方法?这两个方法你要么同时重写,要么都不写,要么同时同时重写,都写上啊,都写上,但你写的话,我也没有说给你多大的压力,说我应该怎么写怎么写,对吧,Idea工具生成一下就行了。
08:06
生成一下就可以了啊行吧,这块的话怎么说呢,咱们这个源代码,咱们其实写代码就这些东西,你不要说感觉很恐惧,说老师讲了很长时间,说这个东西我好难啊,我感觉不会哎,咱们还是害还是害怕这个啊,有些同学因为毕竟他是零基础嘛,是不是来这个map这块你要注意,咱们今天上午其实就是几个例子。啊,听我讲了半天,如果说你这个数据结构没有听懂。对吧?啊,如果你没有听明白,那么我现在只告诉你一件事,什么事咱们第一呢先干啥呀?Map接口里边方法咱们先记住。多练、多敲、多写。第二个字呢,要求你每一个同学必须能够对map集合里边数据进行便利迭代。这两种方式都要会啊。第三个我希望你能掌握的一个结论是这个student这个类当中哈,Code的方法和E方法需要重写。对,其实就三个知识点,你就重写就行了,对吧,重写一下我说了,你如果只重写equal high code的,不重写,你不重写high code的方法,就会导致你有一个你有十个对象是十个内存地址,十个内存地址会产生十个不同的哈希值,十个哈希值如果没有哈希碰撞的前前提下,你可能会生成十个下标,你生成十个下标就会都放进去,而你的ES方法呢。
09:19
Equals方法有可能这十个对象都是true,这十个对象都是一样的,本来应该放一个,结果十个都放进去了,这样不就矛盾了吗?对吧?所以呢,我们的high code要重写,Equals也需要去重写。啊,那重写high呢,是先去重写它,并且它是先被调用的,各位啊,它是会被先调用的。会先去调用这个方法啊,然后再去调equals方法的。啊,然后再去调E方法。对哈希扣的方法调用完之后呢,它得出一个什么呀,哈希值转换成数组下标对吧,这个数组下标有可能会哈希碰撞,也有可能不碰撞啊。看这个具体的哈希算法,对,但是我还是那句话,各位,如果你在同一个链表上,呃,就是如果你的哈希值是一样的,这个哈希值和这个哈希值是一样的,那么你肯定是在同一个列表上,但是如果你的哈希值和这个哈希值不一样,因为哈希碰撞的方式也有可能会导致你怎么着啊,在同一个列表上,但在同一个列表上无所谓,为什么,因为我们会往列表下面直接加就行了,直接往上加就行了。
10:22
还是那句话啊,同一个列表上的哈希值。它可能不一样,因为你有可能碰撞了,但转换到数字下边是一样的,但如果说两个哈希值就是一样,我这个哈希值和这个哈希值一样,那它肯定是在同一个列表上,就不用说了。你像我这个程序,我在重写了high code呀,重写了high code,你再去调的时候,你看其实是这个name,这个name是string嘛,String的high code方已经重写了,所以我们在这个地方在测试这个程序的时候,怎么测的,里边有张三,这个张三这个张三的哈扣和这个张三哈扣的一样的值都是多少负的什么1432604525是不是,哎是这个值和这个值。对,但是你在重启之前,你你你实际上是对象内存地址,这个对象和这个对象内存地址不一样,对吧。
11:05
还是那句话啊,在如果哈气是一样。写上吧,写上啊。对于哈希表数据结构来说。如果,如果O1和O2的。和O2的这个哈希值相同啊,一定是放到同一个单项链表上。啊,当然当然,如果O1和O2的哈希值不同,但由于哈希算法对吧?但由于哈希算法执行结束之后,转换的数组下标可能相同,此时会发生叫做哈希。
12:10
碰撞。哈希碰撞啊,当然,如果O1和O2的哈希值不同,但由于哈希算法执行结束之后的转换的数据下面有可能相同。啊。当然啊,O1和O2的哈义值相同的话,一定是在同一同一个单项列表上面啊,同一个单列表上面,这是肯定,这句话是没毛病的啊,没毛病,哈一碰撞你愿意了解了解,不愿意了解无所谓啊,没关系,没关系,不用管,不用管它啊,你要是说把底层扒过来这个源码看一下map这一块。是吧,我要把这个set集合它底层的一个实现原理从头到尾看一下,Map集合从头到尾看一下啊,当然这个肯定会对你的编码能力有一定的提升啊,因为它底层的实现很复杂。啊,很复杂。但如果说你要没这个精力的话,我觉得你还是先放一放吧,行吧,啊,大部分同学可能还是没有这个啊。
13:07
行吧,这块呢,咱们就说到这儿啊,这是我们今天上午所说的东西,一个是什么呢?是关于我们的一个。这个map接口中的方法,一个是哈希map底层的一个数据啊结构啊,哈希表的数据结构,然后呢,要知道咱们在JDK8之后超过八个元素呢,我们单列表变成这种二叉树的这种情况,要知道它的初始化容量是16,默认加载因子是点七五,那它扩容是多少呢?这个含信M怎么扩容呢?我们可以看看韩M怎么扩容的。嗯。找找。看它扩容怎么扩的。扩容的话,我们应该看一下put方法吧,因为加元素不够的时候,再是不是才扩容啊,它调这个put方法,Put o put value啊,那点过去吧,看看吧,Put value这块呢,就往里边加,往里边加。嗯。
14:01
这块有没有关于扩容的一个代码,大家看看。这个方法。扩容有没有容量上的事儿?循环。Old value。After。Size,诶,这个位置像值是吧?Re size,你看当这个加加size值,如果是大于这个门限值的话,就在re。点过去看一下吧。看这个new new capacity应该是新容量,抖音导容量。嗯,左移一位,二进制左移,你看又又遇到二进制左移的问题是吧,二进制左移表示扩大了二倍呗,是吧,所以新容量是老容量二倍是吧。应该是可以看到啊,这样一个方法。那么这块呢,其实也可以记一下对吧?啊,别往这儿记了,我觉得还是记到这个图上吧,啊扩容是。
15:07
扩容是一次。扩容之后,扩容之后的容量是原容量的二倍啊,是原容量的二倍啊,是原容量的二倍。好,这是这个哈希map。啊。扩容的事儿啊,二倍啊是非线程安全的,各位啊,非限制安全的。
我来说两句