编辑问题以删除我的类比并直接询问。 JDK HashSet
实现如下:
public class HashSet {
private HashMap map;
public HashSet(int capacity) {
map = new HashMap(capacity);
}
public HashSet(int capacity, float loadFactor) {
map = new HashMap(capacity, loadFactor);
}
HashSet(int capacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(capacity, loadFactor);
}
}
LinkedHashSet
的实现方式如下:
public class LinkedHashSet
extends HashSet {
public LinkedHashSet(int capacity) {
super(capacity, 0, true);
}
public LinkedHashSet(int capacity, float loadFactor) {
super(capacity, loadFactor, true);
}
}
班级HashSet
中的第三个构造函数:HashSet(int capacity, loadFactor, boolean dummy)
仅用于帮助LinkedHashSet
班级使用LinkedHashMap
作为支持地图而不是默认HashMap
问题:
map
类型不是更好吗? LinkedHashSet
的双向链表,因为上面的实现范例并没有直观地发生在我身上,何时这样的设计是一个不错的选择呢? / LI>
答案 0 :(得分:2)
你说这不是最好的设计选择。
总结:
HashSet有3个构造函数:
/**
* Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
* 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
* @throws IllegalArgumentException if the initial capacity is less
* than zero, or if the load factor is nonpositive
*/
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
/**
* Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
* the specified initial capacity and default load factor (0.75).
*
* @param initialCapacity the initial capacity of the hash table
* @throws IllegalArgumentException if the initial capacity is less
* than zero
*/
public HashSet(int initialCapacity) {
map = new HashMap<>(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<>(initialCapacity, loadFactor);
}
最后一个有一个额外的参数dummy,它没有被使用,只是让编译器区分具有相同参数的2个构造函数。唯一的区别是更改支持地图的实施。
我们在对象设计方面做得更好,因为这些课程已经写完了。
如果今天重写了,可能会有一个构造函数改为使用Map
,以便任何Map实现都可以用作后备存储:
HashSet(Map<K,V> backingMap);
和/或可能存在多个具有不同名称但与
相同的参数的静态工厂方法 public static HashSet create(int initialCapacity, float loadFactor)
public static HashSet createLinked(int initialCapacity, float loadFactor)
修改强>
JB Nizet提出了一个有趣的观点。当从ObjectInputStream重构一个对象时,HashSet的readObject()
方法具有显式代码,以查看该实例是否属于LinkedHashSet。
// Create backing HashMap
map = (((HashSet<?>)this) instanceof LinkedHashSet ?
new LinkedHashMap<E,Object>(capacity, loadFactor) :
new HashMap<E,Object>(capacity, loadFactor));
这只是真的可能,因为构造函数的伪参数版本是包私有的,因此这些是当前唯一的两种可能的实现。如果没有这种技术,您将无法正确使用ReadObject()。
这可能是Josh Bloch在Effective Java中编写序列化章节的原因。您可能必须使用SerializationProxy(Item 78)才能正确读取LinkedHashSet。