学习自:
http://www.cnblogs.com/skywang12345/p/3311252.html
阅读HashSet的源码发现很有意思,四个`public修饰的构造函数内部全是new一个HashMap的实例,还有一个无修饰的构造函数new了一个LinkedHashMap,而LinkedHashMap又继承自HashMap。也就是说,HashSet是基于HashMap保存数据的。
通读源码发现,内部实现的方法也比HashMap少了许多,而且很多方法其实就是在调用HashMap里的方法。
问题
1.下方代码中为何初始容量是从Math.max((int) (c.size()/.75f) + 1, 16)中选?c.size()/.75f) + 1代表什么?
首先,说明(c.size()/.75f) + 1。
因为从
HashMap的效率(时间成本和空间成本)考虑,HashMap的加载因子是0.75。当HashMap的“阈值”(阈值 =HashMap总的大小 * 加载因子) < “HashMap实际大小”时,就需要将HashMap的容量翻倍。所以,(c.size()/.75f) + 1计算出来的正好是总的空间大小。
接下来,说明为什么是 16 。
因为HashMap的初始容量就是16,所以初始容量只能大于等于16且必须是2的幂。
2.既然HashSet的底层数据结构是HashMap,那么为什么不可以用put方法添加key-value对而只能用add方法添加值呢?
首先,HashMap实现了Map接口,Map接口中定义了put方法而没有add方法;其次,HashSet实现的是Set接口,Set接口又继承自Collection接口,这两接口里只定义了add方法而没有put方法。
虽然HashSet内部通过一个HashMap类型的map变量来保存数据,但是由于该map是私有的,外部无法访问,所以我也无法通过set.map.put(key, value)进行操作!!!
HashSet所提供的add()内部其实是通过map.put()实现的:
由add()方法可以得知,其实例如set.add(0)中的0是放进HashMap中的key里面的,而value则是常量PRESENT(Object的实例)。这也是为什么HashSet只提供了一个keySet集合而没有什么values等集合。
3.HashSet能插入重复值吗?
不可以!前面说了,其实它插入值放在HashMap中的key里,key是不能重复的。
4.HashSet是有序的吗?
不是!关键看add()方法就可以知道它插入数据的顺序了。底层其实还是调用的HashMap的put方法。HashMap的索引由(n - 1) & hash]得到(长度和哈希值执行与运算),这样是无法保证数据间的顺序的。
