Java基础知识_Set集合
一、HashSet剖析
按照国际惯例,我们来看看HashSet的顶部注释
1 /** 2 * This class implements the <tt>Set</tt> interface, backed by a hash table 3 * (actually a <tt>HashMap</tt> instance). It makes no guarantees as to the 4 * iteration order of the set; in particular, it does not guarantee that the 5 * order will remain constant over time. This class permits the <tt>null</tt> 6 * element. 7 * 8 * <p>This class offers constant time performance for the basic operations 9 * (<tt>add</tt>, <tt>remove</tt>, <tt>contains</tt> and <tt>size</tt>), 10 * assuming the hash function disperses the elements properly among the 11 * buckets. Iterating over this set requires time proportional to the sum of 12 * the <tt>HashSet</tt> instance's size (the number of elements) plus the 13 * "capacity" of the backing <tt>HashMap</tt> instance (the number of 14 * buckets). Thus, it's very important not to set the initial capacity too 15 * high (or the load factor too low) if iteration performance is important. 16 * 17 * <p><strong>Note that this implementation is not synchronized.</strong> 18 * If multiple threads access a hash set concurrently, and at least one of 19 * the threads modifies the set, it <i>must</i> be synchronized externally. 20 * This is typically accomplished by synchronizing on some object that 21 * naturally encapsulates the set. 22 * 23 * If no such object exists, the set should be "wrapped" using the 24 * {@link Collections#synchronizedSet Collections.synchronizedSet} 25 * method. This is best done at creation time, to prevent accidental 26 * unsynchronized access to the set:<pre> 27 * Set s = Collections.synchronizedSet(new HashSet(...));</pre> 28 * 29 * <p>The iterators returned by this class's <tt>iterator</tt> method are 30 * <i>fail-fast</i>: if the set is modified at any time after the iterator is 31 * created, in any way except through the iterator's own <tt>remove</tt> 32 * method, the Iterator throws a {@link ConcurrentModificationException}. 33 * Thus, in the face of concurrent modification, the iterator fails quickly 34 * and cleanly, rather than risking arbitrary, non-deterministic behavior at 35 * an undetermined time in the future. 36 * 37 * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed 38 * as it is, generally speaking, impossible to make any hard guarantees in the 39 * presence of unsynchronized concurrent modification. Fail-fast iterators 40 * throw <tt>ConcurrentModificationException</tt> on a best-effort basis. 41 * Therefore, it would be wrong to write a program that depended on this 42 * exception for its correctness: <i>the fail-fast behavior of iterators 43 * should be used only to detect bugs.</i> 44 * 45 * <p>This class is a member of the 46 * <a href="{@docRoot}/../technotes/guides/collections/index.html"> 47 * Java Collections Framework</a>. 48 * 49 * @param <E> the type of elements maintained by this set 50 * 51 * @author Josh Bloch 52 * @author Neal Gafter 53 * @see Collection 54 * @see Set 55 * @see TreeSet 56 * @see HashMap 57 * @since 1.2 58 */
从顶部注释来看我们可以归纳HashSet的要点了
实现Set接口
不保证迭代顺序
允许元素为null
底层实际上是一个HashMap实例
非同步
初始容量非常影响迭代性能
1 public HashSet() { 2 map = new HashMap<>(); 3 }
我们知道Map是一个映射,有value有key的,既然HashSet底层用的是HashMap,那么value在哪里呢???
1 // Dummy value to associate with an Object in the backing Map 2 private static final Object PRESENT = new Object();
value是一个Object,所有的value都是它
所以可以直接总结出:HashSet实际上就是封装了HashMap,操作HashSet元素实际上就是操作HashMap。也是面向对象的一种体现,重用性贼高。
二、TreeSet剖析
按照惯例,我们来看看TreeSet顶部注释
1 /** 2 * A {@link NavigableSet} implementation based on a {@link TreeMap}. 3 * The elements are ordered using their {@linkplain Comparable natural 4 * ordering}, or by a {@link Comparator} provided at set creation 5 * time, depending on which constructor is used. 6 * 7 * <p>This implementation provides guaranteed log(n) time cost for the basic 8 * operations ({@code add}, {@code remove} and {@code contains}). 9 * 10 * <p>Note that the ordering maintained by a set (whether or not an explicit 11 * comparator is provided) must be <i>consistent with equals</i> if it is to 12 * correctly implement the {@code Set} interface. (See {@code Comparable} 13 * or {@code Comparator} for a precise definition of <i>consistent with 14 * equals</i>.) This is so because the {@code Set} interface is defined in 15 * terms of the {@code equals} operation, but a {@code TreeSet} instance 16 * performs all element comparisons using its {@code compareTo} (or 17 * {@code compare}) method, so two elements that are deemed equal by this method 18 * are, from the standpoint of the set, equal. The behavior of a set 19 * <i>is</i> well-defined even if its ordering is inconsistent with equals; it 20 * just fails to obey the general contract of the {@code Set} interface. 21 * 22 * <p><strong>Note that this implementation is not synchronized.</strong> 23 * If multiple threads access a tree set concurrently, and at least one 24 * of the threads modifies the set, it <i>must</i> be synchronized 25 * externally. This is typically accomplished by synchronizing on some 26 * object that naturally encapsulates the set. 27 * If no such object exists, the set should be "wrapped" using the 28 * {@link Collections#synchronizedSortedSet Collections.synchronizedSortedSet} 29 * method. This is best done at creation time, to prevent accidental 30 * unsynchronized access to the set: <pre> 31 * SortedSet s = Collections.synchronizedSortedSet(new TreeSet(...));</pre> 32 * 33 * <p>The iterators returned by this class's {@code iterator} method are 34 * <i>fail-fast</i>: if the set is modified at any time after the iterator is 35 * created, in any way except through the iterator's own {@code remove} 36 * method, the iterator will throw a {@link ConcurrentModificationException}. 37 * Thus, in the face of concurrent modification, the iterator fails quickly 38 * and cleanly, rather than risking arbitrary, non-deterministic behavior at 39 * an undetermined time in the future. 40 * 41 * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed 42 * as it is, generally speaking, impossible to make any hard guarantees in the 43 * presence of unsynchronized concurrent modification. Fail-fast iterators 44 * throw {@code ConcurrentModificationException} on a best-effort basis. 45 * Therefore, it would be wrong to write a program that depended on this 46 * exception for its correctness: <i>the fail-fast behavior of iterators 47 * should be used only to detect bugs.</i> 48 * 49 * <p>This class is a member of the 50 * <a href="{@docRoot}/../technotes/guides/collections/index.html"> 51 * Java Collections Framework</a>. 52 * 53 * @param <E> the type of elements maintained by this set 54 * 55 * @author Josh Bloch 56 * @see Collection 57 * @see Set 58 * @see HashSet 59 * @see Comparable 60 * @see Comparator 61 * @see TreeMap 62 * @since 1.2 63 */
底层是Treemap,实现了NavigableSet接口,根据Comparable在实现自然排序,或者在创建对象时,使用构造方法传递Comparator对象实现排序,时间复杂度是logn,通过compareTo或者compare方法认证元素是否相等。非同步
我们来归纳一下TreeSet
实现NavigableSet接口
可以实现排序功能
底层实际上是一个TreeMap实例
非同步
1 private static final Object PRESENT = new Object(); 2 3 /** 4 * Constructs a set backed by the specified navigable map. 5 */ 6 TreeSet(NavigableMap<E,Object> m) { 7 this.m = m; 8 } 9 10 /** 11 * Constructs a new, empty tree set, sorted according to the 12 * natural ordering of its elements. All elements inserted into 13 * the set must implement the {@link Comparable} interface. 14 * Furthermore, all such elements must be <i>mutually 15 * comparable</i>: {@code e1.compareTo(e2)} must not throw a 16 * {@code ClassCastException} for any elements {@code e1} and 17 * {@code e2} in the set. If the user attempts to add an element 18 * to the set that violates this constraint (for example, the user 19 * attempts to add a string element to a set whose elements are 20 * integers), the {@code add} call will throw a 21 * {@code ClassCastException}. 22 */ 23 public TreeSet() { 24 this(new TreeMap<E,Object>()); 25 }
Map的value是new Object();
实例是new TreeMap<E,Object>()
三、LinkedHashSet剖析
按照国际惯例,看看LinkedHashSet顶部注释:
1 /** 2 * <p>Hash table and linked list implementation of the <tt>Set</tt> interface, 3 * with predictable iteration order. This implementation differs from 4 * <tt>HashSet</tt> in that it maintains a doubly-linked list running through 5 * all of its entries. This linked list defines the iteration ordering, 6 * which is the order in which elements were inserted into the set 7 * (<i>insertion-order</i>). Note that insertion order is <i>not</i> affected 8 * if an element is <i>re-inserted</i> into the set. (An element <tt>e</tt> 9 * is reinserted into a set <tt>s</tt> if <tt>s.add(e)</tt> is invoked when 10 * <tt>s.contains(e)</tt> would return <tt>true</tt> immediately prior to 11 * the invocation.) 12 * 13 * <p>This implementation spares its clients from the unspecified, generally 14 * chaotic ordering provided by {@link HashSet}, without incurring the 15 * increased cost associated with {@link TreeSet}. It can be used to 16 * produce a copy of a set that has the same order as the original, regardless 17 * of the original set's implementation: 18 * <pre> 19 * void foo(Set s) { 20 * Set copy = new LinkedHashSet(s); 21 * ... 22 * } 23 * </pre> 24 * This technique is particularly useful if a module takes a set on input, 25 * copies it, and later returns results whose order is determined by that of 26 * the copy. (Clients generally appreciate having things returned in the same 27 * order they were presented.) 28 * 29 * <p>This class provides all of the optional <tt>Set</tt> operations, and 30 * permits null elements. Like <tt>HashSet</tt>, it provides constant-time 31 * performance for the basic operations (<tt>add</tt>, <tt>contains</tt> and 32 * <tt>remove</tt>), assuming the hash function disperses elements 33 * properly among the buckets. Performance is likely to be just slightly 34 * below that of <tt>HashSet</tt>, due to the added expense of maintaining the 35 * linked list, with one exception: Iteration over a <tt>LinkedHashSet</tt> 36 * requires time proportional to the <i>size</i> of the set, regardless of 37 * its capacity. Iteration over a <tt>HashSet</tt> is likely to be more 38 * expensive, requiring time proportional to its <i>capacity</i>. 39 * 40 * <p>A linked hash set has two parameters that affect its performance: 41 * <i>initial capacity</i> and <i>load factor</i>. They are defined precisely 42 * as for <tt>HashSet</tt>. Note, however, that the penalty for choosing an 43 * excessively high value for initial capacity is less severe for this class 44 * than for <tt>HashSet</tt>, as iteration times for this class are unaffected 45 * by capacity. 46 * 47 * <p><strong>Note that this implementation is not synchronized.</strong> 48 * If multiple threads access a linked hash set concurrently, and at least 49 * one of the threads modifies the set, it <em>must</em> be synchronized 50 * externally. This is typically accomplished by synchronizing on some 51 * object that naturally encapsulates the set. 52 * 53 * If no such object exists, the set should be "wrapped" using the 54 * {@link Collections#synchronizedSet Collections.synchronizedSet} 55 * method. This is best done at creation time, to prevent accidental 56 * unsynchronized access to the set: <pre> 57 * Set s = Collections.synchronizedSet(new LinkedHashSet(...));</pre> 58 * 59 * <p>The iterators returned by this class's <tt>iterator</tt> method are 60 * <em>fail-fast</em>: if the set is modified at any time after the iterator 61 * is created, in any way except through the iterator's own <tt>remove</tt> 62 * method, the iterator will throw a {@link ConcurrentModificationException}. 63 * Thus, in the face of concurrent modification, the iterator fails quickly 64 * and cleanly, rather than risking arbitrary, non-deterministic behavior at 65 * an undetermined time in the future. 66 * 67 * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed 68 * as it is, generally speaking, impossible to make any hard guarantees in the 69 * presence of unsynchronized concurrent modification. Fail-fast iterators 70 * throw <tt>ConcurrentModificationException</tt> on a best-effort basis. 71 * Therefore, it would be wrong to write a program that depended on this 72 * exception for its correctness: <i>the fail-fast behavior of iterators 73 * should be used only to detect bugs.</i> 74 * 75 * <p>This class is a member of the 76 * <a href="{@docRoot}/../technotes/guides/collections/index.html"> 77 * Java Collections Framework</a>. 78 * 79 * @param <E> the type of elements maintained by this set 80 * 81 * @author Josh Bloch 82 * @see Object#hashCode() 83 * @see Collection 84 * @see Set 85 * @see HashSet 86 * @see TreeSet 87 * @see Hashtable 88 * @since 1.4 89 */
迭代有序,维护了一个双项链表,允许为null,性能比HashSet差一点点,因为要维护双向链表,迭代的是双向链表。非同步的。
从顶部注释来看,我们可以归纳LinkedHashSet的要点
迭代是有序的
允许为null
底层实际上是一个HashMap+双向链表的实例(其实就是LinkedHashMap)
非同步
性能比HashSet差一丢丢,因为要维护一个双向链表。
初始容量与迭代无关,LinkedHashSet迭代的是双向链表
四、总结
可以明显的看到,Set集合的底层就是Map,所以没有做什么分析,也没什么好分析的
下面稍微总结一下吧
HashSet
无序,允许为null,底层是HashMap(散列表+红黑树),非线程同步
TreeSet
迭代有序,不允许为null,底层是TreeMap(红黑树),非线程同步
LinkedHashSet:
迭代有序,允许为null,底层是HashMap+双向链表,非线程同步

浙公网安备 33010602011771号