了解完了Hashmap,今天来看一看Hashset。
应该都知道List和Set都实现自Collection,List保证元素的添加顺序,元素可重复。而Set不保证元素的添加顺序,元素不可重复。
上图中可以得知Set在Collection家族中的位置,有两个很重要的实现HashSet和TreeSet。
一个小例子
看第一行代码
Set<String> strSet = new HashSet<>();//new了一个HashSet
new了一个Hashset,即在内存空间中开辟了一块区域给 strSet。点击查看一下HashSet的构造函数。
可以发现,new了一个HashMap,在看一下map是啥。
是一个键为泛型,值为Object类型的HashMap。
new HashSet<>() 时内存图如下所示。
接着看add方法
strSet.add("张三");
进入源码看一看,
原来就是调用底层HashMap的put方法,把"张三"作为key,PRESENT作为value放在hashMap里,Hashmap中,如果put时key重了,会返回被覆盖的value值(oldValue),否则返回null,这儿的HashSet又给包装了一下,如果key没有重(oldValue == null),就返回true,否则返回false。
PRESENT又是什么呢?
PRESENT只是一个final的Object。
此时的内存图是这样的。
依次再添加“李四”,“王五”,“赵六”,内存图如下:
所有元素的value都指向Object对象,HashSet虽然底层是用HashMap来实现的,但由于用不到HashMap的value,所以不会为底层HashMap的每个value分配一个内存空间,因此并不会过多的占用内存。
看下源码中的其他方法
这些方法基本上没什么逻辑代码,就是复用了HashMap里的方法而已。HashSet就是利用HashMap来实现的。这时候我们大胆的猜测一下,TreeSet是不是也是用TreeMap来实现的呢?
还真是的,仔细看一些常用方法也是直接调用Treemap的。
就不一一列举了,可以自己打开源码看一下。
总结:
由于Hashmap中的key是不能重复的,所以Hashset中的值也不能重复,hashmap的存储逻辑也保证了Hashset的无序性。
TreeMap的底层是红黑树,红黑树中节点重复是直接覆盖的,所以保证了TeeeSet的不可重复性,红黑树的存储逻辑也保证了TreeSet的无序性。
HashSet底层声明了一个HashMap,HashSet做了一层包装,操作HashSet里的元素时其实是在操作HashMap里的元素。TreeSet底层也是声明了一个TreeMap,操作TreeSet里的元素其实是操作TreeMap里的元素。