一.概述
Set是通过Map来支持的,Set接口里的所有方法,都委托给内部的Map去实现。
二.HashSet源码
- public class HashSet<E>
- extends AbstractSet<E>
- implements Set<E>, Cloneable, java.io.Serializable
- {
- static final long serialVersionUID = -5024744406713321676L;
- //内部保存一个map引用
- private transient HashMap<E,Object> map;
- //此static final的Object来充当map的value
- private static final Object PRESENT = new Object();
- //构造函数里面初始化一个map
- public HashSet() {
- map = new HashMap<E,Object>();
- }
- public HashSet(Collection<? extends E> c) {
- map = new HashMap<E,Object>(Math.max((int) (c.size()/.75f) + 1, 16));
- addAll(c);
- }
- public HashSet(int initialCapacity, float loadFactor) {
- map = new HashMap<E,Object>(initialCapacity, loadFactor);
- }
- public HashSet(int initialCapacity) {
- map = new HashMap<E,Object>(initialCapacity);
- }
- //此构造函数不是public的
- //它初始化了一个LinkedHashMap,可以猜到LinkedHashSet继承了HashSet
- //HashSet靠HashMap实现,LinkedHashSet靠LinkedHashMap实现,HashSet和LinkedHashSet提供一样的方法
- //LinkedHashSet继承HashSet + 这里的构造函数 = LinkedHashSet只需要构造函数,不需要任何其它代码了
- HashSet(int initialCapacity, float loadFactor, boolean dummy) {
- map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor);
- }
- //迭代Key
- public Iterator<E> iterator() {
- return map.keySet().iterator();
- }
- public int size() {
- return map.size();
- }
- public boolean isEmpty() {
- return map.isEmpty();
- }
- //o就是map里面的key
- public boolean contains(Object o) {
- return map.containsKey(o);
- }
- //添加数据给map去实现就好了,返回boolean
- public boolean add(E e) {
- return map.put(e, PRESENT)==null;
- }
- //删除数据给map去实现就好了返回boolean
- public boolean remove(Object o) {
- return map.remove(o)==PRESENT;
- }
- public void clear() {
- map.clear();
- }
- //clone出一个newSet,给此newSet的成员变量map赋值
- public Object clone() {
- try {
- HashSet<E> newSet = (HashSet<E>) super.clone();
- newSet.map = (HashMap<E, Object>) map.clone();
- return newSet;
- } catch (CloneNotSupportedException e) {
- throw new InternalError();
- }
- }
- //依然是序列化map里面存放的对象
- private void writeObject(java.io.ObjectOutputStream s)
- throws java.io.IOException {
- // Write out any hidden serialization magic
- s.defaultWriteObject();
- // Write out HashMap capacity and load factor
- s.writeInt(map.capacity());
- s.writeFloat(map.loadFactor());
- // Write out size
- s.writeInt(map.size());
- // Write out all elements in the proper order.
- for (Iterator i=map.keySet().iterator(); i.hasNext(); )
- s.writeObject(i.next());
- }
- private void readObject(java.io.ObjectInputStream s)
- throws java.io.IOException, ClassNotFoundException {
- // Read in any hidden serialization magic
- s.defaultReadObject();
- // Read in HashMap capacity and load factor and create backing HashMap
- int capacity = s.readInt();
- float loadFactor = s.readFloat();
- map = (((HashSet)this) instanceof LinkedHashSet ?
- new LinkedHashMap<E,Object>(capacity, loadFactor) :
- new HashMap<E,Object>(capacity, loadFactor));
- // Read in size
- int size = s.readInt();
- // Read in all elements in the proper order.
- for (int i=0; i<size; i++) {
- E e = (E) s.readObject();
- map.put(e, PRESENT);
- }
- }
三.LinkedHashSet源码
- public class LinkedHashSet<E>
- extends HashSet<E> //extends HashSet
- implements Set<E>, Cloneable, java.io.Serializable {
- private static final long serialVersionUID = -2851667679971038690L;
- public LinkedHashSet(int initialCapacity, float loadFactor) {
- super(initialCapacity, loadFactor, true); //dummy=true
- }
- public LinkedHashSet(int initialCapacity) {
- super(initialCapacity, .75f, true);
- }
- public LinkedHashSet() {
- super(16, .75f, true);
- }
- public LinkedHashSet(Collection<? extends E> c) {
- super(Math.max(2*c.size(), 11), .75f, true);
- addAll(c);
- }
四.TreeSet源码
同HashSet一样的道理,就不贴代码了。
五.Set里面是否能存放null
不必刻意去记,把前几篇分析Map的文章搞清楚了,很自然就知道了。
- HashMap允许插入null key,null value,所以HashSet可以插入null数据。
- Hashtable不允许插入null key,null value,如果一个Set用Hashtable去实现,那么这个Set不可以插入null数据。
- LinkedHashMap只是在HashMap基础上加了一个链表,所有的操作同HashMap,所以LinkedHashMap允许插入null key,null value,LinkedHashSet也就插入null数据。
- 自然顺序时TreeMap不允许插入null key,容许插入null value,所以自然顺序时TreeSet不可以插入null数据。