读书人

JDK源码解析 java.util.HashSet种 jdk

发布时间: 2012-12-28 10:29:05 作者: rapoo

JDK源码解析 java.util.HashSet类 jdk1.6

?

/*

?* @(#)HashSet.java 1.37 06/04/21

?*

?* Copyright 2006 Sun Microsystems, Inc. All rights reserved.

?* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.

?*/

?

package java.util;

?

/**

此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素。?

?

此类为基本操作提供了稳定性能,这些基本操作包括 add、remove、contains 和 size,假定哈希函数将这些元素正确地分布在桶中。对此 set 进行迭代所需的时间与 HashSet 实例的大小(元素的数量)和底层 HashMap 实例(桶的数量)的“容量”的和成比例。因此,如果迭代性能很重要,则不要将初始容量设置得太高(或将加载因子设置得太低)。?

?

注意,此实现不是同步的。如果多个线程同时访问一个哈希 set,而其中至少一个线程修改了该 set,那么它必须 保持外部同步。这通常是通过对自然封装该 set 的对象执行同步操作来完成的。如果不存在这样的对象,则应该使用 Collections.synchronizedSet 方法来“包装” set。最好在创建时完成这一操作,以防止对该 set 进行意外的不同步访问:

?

? Set s = Collections.synchronizedSet(new HashSet(...));此类的 iterator 方法返回的迭代器是快速失败 的:在创建迭代器之后,如果对 set 进行修改,除非通过迭代器自身的 remove 方法,否则在任何时间以任何方式对其进行修改,Iterator 都将抛出 ConcurrentModificationException。因此,面对并发的修改,迭代器很快就会完全失败,而不冒将来在某个不确定时间发生任意不确定行为的风险。?

?

注意,迭代器的快速失败行为无法得到保证,因为一般来说,不可能对是否出现不同步并发修改做出任何硬性保证。快速失败迭代器在尽最大努力抛出 ConcurrentModificationException。因此,为提高这类迭代器的正确性而编写一个依赖于此异常的程序是错误做法:迭代器的快速失败行为应该仅用于检测 bug。?

?

此类是 Java Collections Framework 的成员。?

?

?

?

从以下版本开始:?

1.2?

另请参见:

Collection, Set, TreeSet, HashMap, 序列化表格

?

?*/

?

public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable {

static final long serialVersionUID = -5024744406713321676L; //序列化版本号

?

/**

transient是java语言的关键字,变量修饰符,如果用transient声明一个实例变量,当对象存储时,它的值不需要维持。

   Java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据成员,我们不想用serialization机制来保存它。为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。当一个对象被序列化的时候,transient型变量的值不包括在序列化的表示中,然而非transient型的变量是被包括进去的。

*/

private transient HashMap<E, Object> map; //瞬时的HashMap对象

?

// Dummy value to associate with an Object in the backing Map?

//将一个虚拟值与备份的Map对象中的Object对象映射

private static final Object PRESENT = new Object();

?

/**

* Constructs a new, empty set; the backing <tt>HashMap</tt> instance has

* default initial capacity (16) and load factor (0.75).

* 构造一个新的空 set,其底层 HashMap 实例的默认初始容量是 16,加载因子是 0.75。?

*/

public HashSet() {

map = new HashMap<E, Object>(); //可以看到,HashSet是用不使用键值对中的值的HashMap来构造的。即HashSet只是用HashMap中的键来构造。

}

?

/**

构造一个包含指定 collection 中的元素的新 set。使用默认的加载因子 0.75 和足以包含指定 collection 中所有元素的初始容量来创建 HashMap。?

?

参数:

c - 其中的元素将存放在此 set 中的 collection?

抛出:?

NullPointerException - 如果指定的 collection 为 null

?

*/

public HashSet(Collection<? extends E> c) { //先构造一个HashMap,容量为传入的Collection对象的大小除以默认加载因子和16中取较大的值。

map = new HashMap<E, Object>(Math.max((int) (c.size() / .75f) + 1, 16));

addAll(c); //然后将Collection中的元素加入进来。

}

?

/**

构造一个新的空 set,其底层 HashMap 实例具有指定的初始容量和指定的加载因子。?

?

参数:

initialCapacity - 哈希映射的初始容量

loadFactor - 哈希映射的加载因子?

抛出:?

IllegalArgumentException - 如果初始容量小于零,或者加载因子为非正数

?

*/

public HashSet(int initialCapacity, float loadFactor) {

map = new HashMap<E, Object>(initialCapacity, loadFactor);

}

?

/**

构造一个新的空 set,其底层 HashMap 实例具有指定的初始容量和默认的加载因子(0.75)。?

?

参数:

initialCapacity - 哈希表的初始容量?

抛出:?

IllegalArgumentException - 如果初始容量小于零

?

*/

public HashSet(int initialCapacity) {

map = new HashMap<E, Object>(initialCapacity);

}

?

/**

* Constructs a new, empty linked hash set. ?(This package private

* constructor is only used by LinkedHashSet.) The backing

* HashMap instance is a LinkedHashMap with the specified initial

* capacity and the specified load factor.

*

* @param ? ? ?initialCapacity ? the initial capacity of the hash map

* @param ? ? ?loadFactor ? ? ? ?the load factor of the hash map

* @param ? ? ?dummy ? ? ? ? ? ? ignored (distinguishes this

* ? ? ? ? ? ? constructor from other int, float constructor.)

* @throws ? ? IllegalArgumentException if the initial capacity is less

* ? ? ? ? ? ? than zero, or if the load factor is nonpositive

* 默认权限的构造方法。

*/

HashSet(int initialCapacity, float loadFactor, boolean dummy) {

map = new LinkedHashMap<E, Object>(initialCapacity, loadFactor);

}

?

/**

返回对此 set 中元素进行迭代的迭代器。返回元素的顺序并不是特定的。?

?

指定者:

接口 Iterable<E> 中的 iterator

指定者:

接口 Collection<E> 中的 iterator

指定者:

接口 Set<E> 中的 iterator

指定者:

类 AbstractCollection<E> 中的 iterator

返回:

对此 set 中元素进行迭代的 Iterator

另请参见:

ConcurrentModificationException

?

* @see ConcurrentModificationException

*/

public Iterator<E> iterator() {

return map.keySet().iterator(); //可以看到,这里就是迭代HashMap中的键key。

}

?

/**

返回此 set 中的元素的数量(set 的容量)。?

?

指定者:

接口 Collection<E> 中的 size

指定者:

接口 Set<E> 中的 size

指定者:

类 AbstractCollection<E> 中的 size

返回:

此 set 中的元素的数量(set 的容量)

?

*/

public int size() {?

return map.size(); //可以看到,HashSet的大小即为该HashSet使用的HashMap的大小。

}

?

/**

如果此 set 不包含任何元素,则返回 true。?

?

指定者:

接口 Collection<E> 中的 isEmpty

指定者:

接口 Set<E> 中的 isEmpty

覆盖:

类 AbstractCollection<E> 中的 isEmpty

返回:

如果此 set 不包含任何元素,则返回 true

?

*/

public boolean isEmpty() { //同样,判断是否为空也是通过HashMap来操作的。

return map.isEmpty();

}

?

/**

如果此 set 包含指定元素,则返回 true。 更确切地讲,当且仅当此 set 包含一个满足 (o==null ? e==null : o.equals(e)) 的 e 元素时,返回 true。?

?

指定者:

接口 Collection<E> 中的 contains

指定者:

接口 Set<E> 中的 contains

覆盖:

类 AbstractCollection<E> 中的 contains

参数:

o - 其在此 set 中的存在已得到测试的元素?

返回:

如果此 set 包含指定元素,则返回 true

?

*/

public boolean contains(Object o) {?

return map.containsKey(o); //调用的是HashMap的containsKey方法。

}

?

/**

如果此 set 中尚未包含指定元素,则添加指定元素。更确切地讲,如果此 set 没有包含满足 (e==null ? e2==null : e.equals(e2)) 的元素 e2,则向此 set 添加指定的元素 e。如果此 set 已包含该元素,则该调用不更改 set 并返回 false。?

?

指定者:

接口 Collection<E> 中的 add

指定者:

接口 Set<E> 中的 add

覆盖:

类 AbstractCollection<E> 中的 add

参数:

e - 将添加到此 set 中的元素?

返回:

如果此 set 尚未包含指定元素,则返回 true

?

*/

public boolean add(E e) {

return map.put(e, PRESENT) == null; //调用的是HashMap的put方法。

}

?

/**

如果指定元素存在于此 set 中,则将其移除。更确切地讲,如果此 set 包含一个满足 (o==null ? e==null : o.equals(e)) 的元素 e,则将其移除。如果此 set 已包含该元素,则返回 true(或者:如果此 set 因调用而发生更改,则返回 true)。(一旦调用返回,则此 set 不再包含该元素)。?

?

指定者:

接口 Collection<E> 中的 remove

指定者:

接口 Set<E> 中的 remove

覆盖:

类 AbstractCollection<E> 中的 remove

参数:

o - 如果存在于此 set 中则需要将其移除的对象?

返回:

如果 set 包含指定元素,则返回 true

?

*/

public boolean remove(Object o) {

return map.remove(o) == PRESENT; //调用的是HashMap的remove方法。

}

?

/**

从此 set 中移除所有元素。此调用返回后,该 set 将为空。?

?

指定者:

接口 Collection<E> 中的 clear

指定者:

接口 Set<E> 中的 clear

覆盖:

类 AbstractCollection<E> 中的 clear

?

*/

public void clear() {?

map.clear(); //调用的是HashMap的clear方法。

}

?

/**

返回此 HashSet 实例的浅表副本:并没有复制这些元素本身。?

?

覆盖:

类 Object 中的 clone

返回:

此 set 的浅表副本

另请参见:

Cloneable

?

*/

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();

}

}

?

/**

* Save the state of this <tt>HashSet</tt> instance to a stream (that is,

* serialize it).

*

* @serialData The capacity of the backing <tt>HashMap</tt> instance

* ? (int), and its load factor (float) are emitted, followed by

* ? the size of the set (the number of elements it contains)

* ? (int), followed by all of its elements (each an Object) in

* ? ? ? ? ? ? no particular order.

*/

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());

}

?

/**

* Reconstitute the <tt>HashSet</tt> instance from a stream (that is,

* deserialize it).

*/

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);

}

}

}


读书人网 >编程

热点推荐