1.散列机制是如何工作的?
2.在使用散列容器时怎样编写hashCode()和equals()方法。
- 带有hash思想的容器,要求必须定义hashCode()。
- 你必须为散列存储和树型存储都创建一个equals()方法,但是hashCode()只有在这个类将会被置于HashSet或者LinkedHashSet中时才是必须的。
- 散列码是“相对唯一”的、用以代表对象的int值,他是通过将该对象的某些信息进行转换而生成的。
- HashCode()是根类Object中的方法,因此所有java对象都能产生散列码。
散列为何速度快?
- 散列的价值在于速度:散列使得查询得以快速进行。
(1)散列将键保存在某处,以便能够很快找到。存储一组元素最快的数据结构是数组,所以使用它来表示键的信息。但是因为数组不能调整容量,因此就有一个问题:我们希望在Map中保存数量不确定的值,但是如果键的数量被数组的容量限制了,该怎么办?
答案就是:数组并不保存键本身。而是通过键对象生成一个数字,将其 作为数组的下标。这个数字就是散列码。由定义在Object中的、且可能由你的类覆盖的hashCode方法生成。
(2)为解决数组容量被固定的问题,不同的键可以产生相同的下标。也就是说,可能会有冲突。因此,数组多大就不重要了,任何键总能在数组中找到它的位置。
(3)于是查询一个值的过程首先就是计算散列码,然后使用散列码查询数组。如果能够保证没有冲突(如果哦值的数量是固定的,那么就有可能),那可就有了一个完美的散列函数,但是这种情况只是特例。通常,冲突由 外部连接 处理:数组并不直接保存值,而是保存值的list。然后对list中的值使用equals()方法进行线性的查询。这部分的查询自然会比较慢,但是,如果散列函数好的话,数组的每个位置就只有少量的值。因此,不是查询整个list,而是快速跳到数组的某个位置,只对很少的元素进行比较。这便是HashMap会如此快的原因。
(4)由于散列表中的“槽位(slot)”通常称为“桶位(bucket)”,因此我们将表示实际散列表的数组名命为bucket。为了使散列分布均匀,桶的数量通常使用质数。注意,为了能够自动处理冲突,使用了一个LinkedList的数组;每一个新的元素只是直接添加到list末尾的某个特定桶位中。
(5)另外,根据自己实际情况,可以对HashMap进行调优
如何编写hashCode()方法
(1)设计hashCode()时最重要的因素就是:无论何时,对同一个对象调用hashCode()都应该生成同样的值。它必须基于对象的内容生成散列码。散列码不必是唯一的,但是通过hashCode()和equals(),必须能够完全确定对象的身份。注意散列码是一个int对象。
(2)好的hashCode()应该产生分布均匀的散列码。如果散列码都集中在一块,那么HashMap或者HashSet在某些区域的负载会很重,这样就不如分布均匀的散列码函数快。