HashSet的实现基于HashMap
看几个简单的初始化方法
public HashSet() { map = new HashMap<>(); } public HashSet(Collection<? extends E> c) { map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16)); addAll(c); } public HashSet(int initialCapacity, float loadFactor) { map = new HashMap<>(initialCapacity, loadFactor); } public HashSet(int initialCapacity) { map = new HashMap<>(initialCapacity); } HashSet(int initialCapacity, float loadFactor, boolean dummy) { map = new LinkedHashMap<>(initialCapacity, loadFactor); }
可以看到HashSet的所有初始化,其实都在初始化hashmap,可以看出HashSet和HashMap是has-a的形式。最后一个初始化的是使用LinkedHashMap,dummy参数只是为了做区分构造函数,可以忽略。
看一个HashSet的add操作
private static final Object PRESENT = new Object();
public boolean add(E e) { return map.put(e, PRESENT)==null; }
可以看出,add时,将添加的元素作为hashmap的键值,PERSENT作为默认的值,put到map中。
例如contains、remove等类似的处理,将值作为map的key值在map中操作。
不过HashSet继承了AbstractSet,AbstractSet继承了AbstractCollection。
例如刚刚的构造函数里有个addAll方法,调用的是父类AbstractCollection中的addAll方法
public boolean addAll(Collection<? extends E> c) { boolean modified = false; for (E e : c) if (add(e)) modified = true; return modified; }
而add(e)在HashSet又得到了重写。
再看看LinkedHashSet这个类,这个类的构造函数都调用父类HashSet的特殊构造方法
public LinkedHashSet(int initialCapacity, float loadFactor) { super(initialCapacity, loadFactor, true); } public LinkedHashSet(int initialCapacity) { super(initialCapacity, .75f, true); } public LinkedHashSet(Collection<? extends E> c) { super(Math.max(2*c.size(), 11), .75f, true); addAll(c); }
而HashSet这个构造方法是通过使用LinkedHashMap来实现的