你是对的,这不是最好的设计选择。
总结一下:
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 提出了一个有趣的观点。HashSet 的readObject()
方法在从 ObjectInputStream 重构对象时具有显式代码,以查看“this”实例是否属于 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。