Java容器类的用途是“保存对象”,分为两类:Map——存储“键值对”组成的对象;Collection——存储独立元素。Collection又可以分为List和Set两大块。List保持元素的顺序,而Set不能有重复的元素。
本文分析Set中最常用的HashSet类,并简单介绍和对比LinkedHashSet。
首先对Set接口进行简要的说明。
存入Set的每个元素必须是惟一的,因为Set不保存重复元素。加入Set的元素必须定义equals()方法以确保对象的唯一性。Set不保证维护元素的次序。Set与Collection有完全一样的接口。
在没有其他限制的情况下需要Set时应尽量使用HashSet,因为它对速度进行了优化。
下面是HashSet的定义:
public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.SerializableHashSet继承了AbstractSet,实现了Set接口。其实AbstractSet已经实现Set接口了。AbstractSet继承自AbstractCollection,而AbstractCollection实现了Collection接口的部分方法,而Set接口和Collection接口完全一致,所以AbstractSet只是实现了AbstractCollection没有实现的Set接口的方法和重写了部分AbstractCollection已经实现的方法。
private transient HashMap<E,Object> map; private static final Object PRESENT = new Object();
// 构造方法一:调用默认的HashMap构造方法初始化map public HashSet() { map = new HashMap<E,Object>(); } // 构造方法二:根据给定的Collection参数调用HashMap(int initialCapacity)的构造方法创建一个HashMap(这个构造方法的HashMap的源码分析里已经描述过了) // 调用addAll方法将c中的元素添加到HashSet对象中 public HashSet(Collection<? extends E> c) { map = new HashMap<E,Object>(Math.max((int) (c.size()/.75f) + 1, 16)); addAll(c); } // 构造方法三:构造一个指定初始化容量和负载因子的HashMap public HashSet(int initialCapacity, float loadFactor) { map = new HashMap<E,Object>(initialCapacity, loadFactor); } // 构造方法四:构造一个指定初始化容量的HashMap public HashSet(int initialCapacity) { map = new HashMap<E,Object>(initialCapacity); } // 构造方法五:构造一个指定初始化容量和负载因子的LinkedHashMap // dummy参数被忽略,只是用于区分其他的,包含一个int、float参数的构造方法 HashSet(int initialCapacity, float loadFactor, boolean dummy) { map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor); }
public boolean addAll(Collection<? extends E> c) { boolean modified = false; Iterator<? extends E> e = c.iterator(); while (e.hasNext()) { if (add(e.next())) modified = true; } return modified; }
public boolean add(E e) { return map.put(e, PRESENT)==null; }
public Iterator<E> iterator() { return map.keySet().iterator(); }
public int size() { return map.size(); }
public boolean isEmpty() { return map.isEmpty(); }
public boolean contains(Object o) { return map.containsKey(o); } public void clear() { map.clear(); } 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(); } }
public boolean remove(Object o) { return map.remove(o)==PRESENT; }
public class LinkedHashSet<E> extends HashSet<E> implements Set<E>, Cloneable, java.io.Serializable { public LinkedHashSet(int initialCapacity, float loadFactor) { super(initialCapacity, loadFactor, 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); } }
HashSet(int initialCapacity, float loadFactor, boolean dummy) { map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor); }
Set<String> linkedSet = new LinkedHashSet<String>(); linkedSet.add("First"); linkedSet.add("Second"); linkedSet.add("Thrid"); linkedSet.add("Fourth"); System.out.println("LinkedHashSet:"+linkedSet); Set<String> hashSet = new HashSet<String>(); hashSet.add("First"); hashSet.add("Second"); hashSet.add("Thrid"); hashSet.add("Fourth"); System.out.println("HashSet:"+hashSet); // LinkedHashSet:[First, Second, Thrid, Fourth] // HashSet:[Fourth, Second, Thrid, First]
源码详情参考:http://tech.ddvip.com/2013-11/1385654597206522.html