在存放集合这种数据的时候,我们可以选择List和Set两种形式,当然,Java当中它们不是具体的实现类.我们可以使用具体的实现类进行数据的存储.
但是List和Set的最显著区别,应该是,List可以放置相同的元素,Set只能放置不同的元素.也就是说Set里面的元素具有唯一性.
当然ArrayList和LinkedList也只是具体的实现形式不同了.我们也可以实现一个ArraySet或LinkedSet.但是.我们会发现一个比较严重的问题.就是.当我们向ArraySet(或LinkedSet)里面添加元素的时候,我们要逐个比较里面的所有已有元素.这样,当集合中数量非常多的时候,比较次数也会直线上升.也就是说,当我们结合中有10000个元素的时候,我再添加一个元素,要首先比较最多10000次才能确定我要添加的元素是否已经存在了,这会严重影响集合的性能.
为了更快捷的检索数据,我们才引进了hashCode的概念,每个Set里面的元素都会有一个hashCode的值,我们可以按照hashCode的值来存储集合里面的元素.如果要检索集合里面是否存在要添加的元素,只要先将该元素的hashCode值算出来,再到相应的位置进行查找,就可以了.对于相同hashCode的不同元素,我们把这个位置,按照链表的形式进行存放.这样,就可以很大程度上减少比较的次数.举个例子:
我们Set集合里面可能已经10000个不同的元素了.当添加新元素的时候,我们根据新元素的hashCode值,找到相应的位置,这个位置所对应的链表里面,可能只有五个元素,那么,我们只要比较5次,就可以判断整个集合中是否已经存在该元素了,因为,相同元素的hashCode一定是相同的.呵呵.为了使根据hashCode确定位置的速度更快,我们采用数组的下标来表示位置,数组里面存放链表.下标都是自然数,所以,要把hashCode进行向数组下标的映射转换(其实就是与运算).
最后,来谈谈,什么情况下重写hashCode,我们知道,自然情况下,hashCode所产生的值是很有规律的,这样的话,拥有10000个元素的Set,可能有9000个都在同一个位置上,这样,再加一个相同hashCode的元素时,那可能要比较90000次了.所以,我们要自己定义hashCode使得这些元素的hashCode在hashSet里面存储更加分散.不过Java的HashSet里面,已经有一个方法,将元素的hashCode做打散处理了,这个方法对于默认的hashCode还是比较有效果的.对于熟悉这些内容的程序员,为了程序的效率更高,可以重写hashCode方法.但是,不能使用随机数充当hashCode,每个元素,都应该对应唯一的一个hashCode,一个hashCode可以对应多个元素.
也可以这么说,只要对象内容一样,我们就有必要重写它的hashCode,hashCode代表的是对象的内存地址,或者说内存地址根据这个hash码得到, 一般的集合都重写了hashCode方法,而当我们自定义对象的时候就要重写hasdCode方法,保证内容一样的对象算出相同的hash码。hash码的用处只体现在需要散列的地方,如hashSet、hashMap,提高用户查找速度 |