1、首先先理一下java的集合关系,Collection和Map接口是所有集合接口的根结点,其他集合都直接或者间接的实现了他们中的一个;collection下有:list(元素可重复)和set(不可重复),queue等,他们下面又有各自的分支,hashset就属于set的实现;map下有treemap、hashmap,hashtable等。
2、hashmap以键值对存放数据的集合,key不能重复,value可以,当我们new hashmap时,根据源码给我们创建了一个entry型的数组,Entry是什么?他是Map下的一个静态类,以key-value的形式存在,所以由此可知,hashmap原来也是数组,只是数组元素是Entry型。默认的capacity为16,默认的负载因子为0.75,从源码看出,所谓负载因子就是去时间和空间效率的一个平衡点,因子大,哈希冲突概率增大,时间长,但是空间相对减少。当我们put时,只关注key就行,源码中对key的hashcode值求hash值,进行了两次hash,然后根据hash出的值计算哈希表的索引,然后对索引所对应的Entry进行遍历,如果不为空就进行equals判断,如果equals返回true就覆盖value,说明是同一个对象,返回false,则生成一个Entry链,新添加的为头结点,除了保存自身的value索引外,还保存着下个Entry的引用(这也就是解决了哈希冲突)。当我们get时,根据hashcode的hash值找到bucket,如果是个Entry链,就用equals比较,返回对应的value。另外遍历hashmap可以有keySet、entrySet、values三个方法就行迭代。
3、当你理解了hashmap后你会发现hashset不就是对hashmap的分装吗。只用到map的key值添加时如果返回为空则添加成功,因为hashmap添加时如果索引中没有Entry返回的就是null。其他返回为false,但是当出现hash冲突时岂不是存不进去了,这点不懂。
4、hashtable实现和hashmap类似,只是方法实现了同步,直接用hashcode求索引。