一.关于hashCode
1.hashCode的存在是主要用于查找的快捷性。如Hashtable,HashMap。hashCode是用来在散列存储结构确定对象的存储地址的。
2.如果两个对象相同,就是适用于equals方法。那么两个对象的hashCode一定要相同。
3.如果对象的equals方法被重写了,那么对象的hashCode也尽量重写。并且hashCode使用的对象。一定要要和eauals方法中使用的一直,’
否则就会违反上面的第二点。
4.两个对象的hashCode相同,并不一定表示两个对象相同。也就是不一定适用于equals方法,只能够说明这两个对象
在散列存储结构中。如Hashtable,他们存放在同一个篮子里。
5.
在归纳一下hashCode就是查找使用,而equals是用于比较两个对象是都相等的。
1.hashcode是用来查找的,如果你学过数据结构就应该知道,在查找和排序这一章有 例如内存中有这样的位置 0 1 2 3 4 5 6 7 而我有个类,这个类有个字段叫ID,我要把这个类存放在以上8个位置之一,如果不用hashcode而任意存放,那么当查找时就需要到这八个位置里挨个去找,或者用二分法一类的算法。 但如果用hashcode那就会使效率提高很多。 我们这个类中有个字段叫ID,那么我们就定义我们的hashcode为ID%8,然后把我们的类存放在取得得余数那个位置。比如我们的ID为9,9除8的余数为1,那么我们就把该类存在1这个位置,如果ID是13,求得的余数是5,那么我们就把该类放在5这个位置。这样,以后在查找该类时就可以通过ID除 8求余数直接找到存放的位置了。 2.但是如果两个类有相同的hashcode怎么办那(我们假设上面的类的ID不是唯一的),例如9除以8和17除以8的余数都是1,那么这是不是合法的,回答是:可以这样。那么如何判断呢?在这个时候就需要定义 equals了。 也就是说,我们先通过 hashcode来判断两个类是否存放某个桶里,但这个桶里可能有很多类,那么我们就需要再通过 equals 来在这个桶里找到我们要的类。 那么。重写了equals(),为什么还要重写hashCode()呢? 想想,你要在一个桶里找东西,你必须先要找到这个桶啊,你不通过重写hashcode()来找到桶,光重写equals()有什么用啊 |
Entry:键值对 对象
在map类设计是:提供了一个嵌套接口(static修饰的接口):Entry将键值对的对应关系封装成了对象,
即就是键值对对象,这样我们在遍历遍历Map集合时,既可以从每一个键值对对象获取对应的键与对应的值。
HashMap底层就是一个数组结构,数组中的每一项又是一个链表。当新建一个HashMap的时候,就会初始化一个数组。
我们看过的源码的时候,他自己定义Entry的数组,他自己的Entry实现了是Map.Entry<K,V>,
这个类里面定义了一个K key,V value, 持有指向下一个元素的next的引用。还有一个final 的hash.Map.Entry就是一个key-value
对。这就构成了链表。
根据hash值得到这个元素在数组中的位置,如果数组改位置上已经存放有其他元素了,那么在这个位置上的元素讲义链表的形式
存放,新加入的放在链头。最先加入的就被挤到了链尾巴了。这个数组该位置上没有元素,就直接将该元素放在该位置上。大
归纳起来简单来说HashMap在基层将key-value当成一个整体进行处理,这个整体就是一个entry对象。HashMap就是一个Entry[]数组来保存
所有的key-value对。当需要存储一个Entry对象是,会根据hasg算法来决定其在数组中的数组位置,
在根据equals方法其在该数组位置上链表中的位置。当我们需要Entry是,也会根据hash算法在其数组中的
存储位置,在根据equals方法在该位置上的链表中取出该Entry.
总结:HashMap的实现原理
概括的说,HashMap
是一个关联数组、哈希表,它是线程不安全的,允许key为null,value为null。遍历时无序。
其底层数据结构是数组称之为哈希桶,每个桶里面放的是链表,链表中的每个节点,就是哈希表中的每个元素。
在JDK8中,当链表长度达到8,会转化成红黑树,以提升它的查询、插入效率,它实现了Map<K,V>, Cloneable, Serializable
接口。
1.利用key的hashCode重新hash计算出当前对象的元素在数组中的下标。
2.存储时,如果出现hash值相同的key,此时有两种情况。(1)如果key相同,则覆盖原始值。
如何key不相同,则当前的key-value放入链表中。
3.获取是,直接知道hash值对应的下标,早进一步判断key是否相同,从而找到相应值。