📄 abstracthashedmap.java
字号:
* Updates an existing key-value mapping to change the value.
* <p>
* This implementation calls <code>setValue()</code> on the entry.
* Subclasses could override to handle changes to the map.
*
* @param entry the entry to update
* @param newValue the new value to store
*/
protected void updateEntry(HashEntry entry, Object newValue) {
entry.setValue(newValue);
}
/**
* Reuses an existing key-value mapping, storing completely new data.
* <p>
* This implementation sets all the data fields on the entry.
* Subclasses could populate additional entry fields.
*
* @param entry the entry to update, not null
* @param hashIndex the index in the data array
* @param hashCode the hash code of the key to add
* @param key the key to add
* @param value the value to add
*/
protected void reuseEntry(HashEntry entry, int hashIndex, int hashCode, Object key, Object value) {
entry.next = data[hashIndex];
entry.hashCode = hashCode;
entry.key = key;
entry.value = value;
}
//-----------------------------------------------------------------------
/**
* Adds a new key-value mapping into this map.
* <p>
* This implementation calls <code>createEntry()</code>, <code>addEntry()</code>
* and <code>checkCapacity()</code>.
* It also handles changes to <code>modCount</code> and <code>size</code>.
* Subclasses could override to fully control adds to the map.
*
* @param hashIndex the index into the data array to store at
* @param hashCode the hash code of the key to add
* @param key the key to add
* @param value the value to add
*/
protected void addMapping(int hashIndex, int hashCode, Object key, Object value) {
modCount++;
HashEntry entry = createEntry(data[hashIndex], hashCode, key, value);
addEntry(entry, hashIndex);
size++;
checkCapacity();
}
/**
* Creates an entry to store the key-value data.
* <p>
* This implementation creates a new HashEntry instance.
* Subclasses can override this to return a different storage class,
* or implement caching.
*
* @param next the next entry in sequence
* @param hashCode the hash code to use
* @param key the key to store
* @param value the value to store
* @return the newly created entry
*/
protected HashEntry createEntry(HashEntry next, int hashCode, Object key, Object value) {
return new HashEntry(next, hashCode, key, value);
}
/**
* Adds an entry into this map.
* <p>
* This implementation adds the entry to the data storage table.
* Subclasses could override to handle changes to the map.
*
* @param entry the entry to add
* @param hashIndex the index into the data array to store at
*/
protected void addEntry(HashEntry entry, int hashIndex) {
data[hashIndex] = entry;
}
//-----------------------------------------------------------------------
/**
* Removes a mapping from the map.
* <p>
* This implementation calls <code>removeEntry()</code> and <code>destroyEntry()</code>.
* It also handles changes to <code>modCount</code> and <code>size</code>.
* Subclasses could override to fully control removals from the map.
*
* @param entry the entry to remove
* @param hashIndex the index into the data structure
* @param previous the previous entry in the chain
*/
protected void removeMapping(HashEntry entry, int hashIndex, HashEntry previous) {
modCount++;
removeEntry(entry, hashIndex, previous);
size--;
destroyEntry(entry);
}
/**
* Removes an entry from the chain stored in a particular index.
* <p>
* This implementation removes the entry from the data storage table.
* The size is not updated.
* Subclasses could override to handle changes to the map.
*
* @param entry the entry to remove
* @param hashIndex the index into the data structure
* @param previous the previous entry in the chain
*/
protected void removeEntry(HashEntry entry, int hashIndex, HashEntry previous) {
if (previous == null) {
data[hashIndex] = entry.next;
} else {
previous.next = entry.next;
}
}
/**
* Kills an entry ready for the garbage collector.
* <p>
* This implementation prepares the HashEntry for garbage collection.
* Subclasses can override this to implement caching (override clear as well).
*
* @param entry the entry to destroy
*/
protected void destroyEntry(HashEntry entry) {
entry.next = null;
entry.key = null;
entry.value = null;
}
//-----------------------------------------------------------------------
/**
* Checks the capacity of the map and enlarges it if necessary.
* <p>
* This implementation uses the threshold to check if the map needs enlarging
*/
protected void checkCapacity() {
if (size >= threshold) {
int newCapacity = data.length * 2;
if (newCapacity <= MAXIMUM_CAPACITY) {
ensureCapacity(newCapacity);
}
}
}
/**
* Changes the size of the data structure to the capacity proposed.
*
* @param newCapacity the new capacity of the array (a power of two, less or equal to max)
*/
protected void ensureCapacity(int newCapacity) {
int oldCapacity = data.length;
if (newCapacity <= oldCapacity) {
return;
}
if (size == 0) {
threshold = calculateThreshold(newCapacity, loadFactor);
data = new HashEntry[newCapacity];
} else {
HashEntry oldEntries[] = data;
HashEntry newEntries[] = new HashEntry[newCapacity];
modCount++;
for (int i = oldCapacity - 1; i >= 0; i--) {
HashEntry entry = oldEntries[i];
if (entry != null) {
oldEntries[i] = null; // gc
do {
HashEntry next = entry.next;
int index = hashIndex(entry.hashCode, newCapacity);
entry.next = newEntries[index];
newEntries[index] = entry;
entry = next;
} while (entry != null);
}
}
threshold = calculateThreshold(newCapacity, loadFactor);
data = newEntries;
}
}
/**
* Calculates the new capacity of the map.
* This implementation normalizes the capacity to a power of two.
*
* @param proposedCapacity the proposed capacity
* @return the normalized new capacity
*/
protected int calculateNewCapacity(int proposedCapacity) {
int newCapacity = 1;
if (proposedCapacity > MAXIMUM_CAPACITY) {
newCapacity = MAXIMUM_CAPACITY;
} else {
while (newCapacity < proposedCapacity) {
newCapacity <<= 1; // multiply by two
}
if (newCapacity > MAXIMUM_CAPACITY) {
newCapacity = MAXIMUM_CAPACITY;
}
}
return newCapacity;
}
/**
* Calculates the new threshold of the map, where it will be resized.
* This implementation uses the load factor.
*
* @param newCapacity the new capacity
* @param factor the load factor
* @return the new resize threshold
*/
protected int calculateThreshold(int newCapacity, float factor) {
return (int) (newCapacity * factor);
}
//-----------------------------------------------------------------------
/**
* Gets the <code>next</code> field from a <code>HashEntry</code>.
* Used in subclasses that have no visibility of the field.
*
* @param entry the entry to query, must not be null
* @return the <code>next</code> field of the entry
* @throws NullPointerException if the entry is null
* @since Commons Collections 3.1
*/
protected HashEntry entryNext(HashEntry entry) {
return entry.next;
}
/**
* Gets the <code>hashCode</code> field from a <code>HashEntry</code>.
* Used in subclasses that have no visibility of the field.
*
* @param entry the entry to query, must not be null
* @return the <code>hashCode</code> field of the entry
* @throws NullPointerException if the entry is null
* @since Commons Collections 3.1
*/
protected int entryHashCode(HashEntry entry) {
return entry.hashCode;
}
/**
* Gets the <code>key</code> field from a <code>HashEntry</code>.
* Used in subclasses that have no visibility of the field.
*
* @param entry the entry to query, must not be null
* @return the <code>key</code> field of the entry
* @throws NullPointerException if the entry is null
* @since Commons Collections 3.1
*/
protected Object entryKey(HashEntry entry) {
return entry.key;
}
/**
* Gets the <code>value</code> field from a <code>HashEntry</code>.
* Used in subclasses that have no visibility of the field.
*
* @param entry the entry to query, must not be null
* @return the <code>value</code> field of the entry
* @throws NullPointerException if the entry is null
* @since Commons Collections 3.1
*/
protected Object entryValue(HashEntry entry) {
return entry.value;
}
//-----------------------------------------------------------------------
/**
* Gets an iterator over the map.
* Changes made to the iterator affect this map.
* <p>
* A MapIterator returns the keys in the map. It also provides convenient
* methods to get the key and value, and set the value.
* It avoids the need to create an entrySet/keySet/values object.
* It also avoids creating the Map.Entry object.
*
* @return the map iterator
*/
public MapIterator mapIterator() {
if (size == 0) {
return EmptyMapIterator.INSTANCE;
}
return new HashMapIterator(this);
}
/**
* MapIterator implementation.
*/
protected static class HashMapIterator extends HashIterator implements MapIterator {
protected HashMapIterator(AbstractHashedMap parent) {
super(parent);
}
public Object next() {
return super.nextEntry().getKey();
}
public Object getKey() {
HashEntry current = currentEntry();
if (current == null) {
throw new IllegalStateException(AbstractHashedMap.GETKEY_INVALID);
}
return current.getKey();
}
public Object getValue() {
HashEntry current = currentEntry();
if (current == null) {
throw new IllegalStateException(AbstractHashedMap.GETVALUE_INVALID);
}
return current.getValue();
}
public Object setValue(Object value) {
HashEntry current = currentEntry();
if (current == null) {
throw new IllegalStateException(AbstractHashedMap.SETVALUE_INVALID);
}
return current.setValue(value);
}
}
//-----------------------------------------------------------------------
/**
* Gets the entrySet view of the map.
* Changes made to the view affect this map.
* To simply iterate through the entries, use {@link #mapIterator()}.
*
* @return the entrySet view
*/
public Set entrySet() {
if (entrySet == null) {
entrySet = new EntrySet(this);
}
return entrySet;
}
/**
* Creates an entry set iterator.
* Subclasses can override this to return iterators with different properties.
*
* @return the entrySet iterator
*/
protected Iterator createEntrySetIterator() {
if (size() == 0) {
return EmptyIterator.INSTANCE;
}
return new EntrySetIterator(this);
}
/**
* EntrySet implementation.
*/
protected static class EntrySet extends AbstractSet {
/** The parent map */
protected final AbstractHashedMap parent;
protected EntrySet(AbstractHashedMap parent) {
super();
this.parent = parent;
}
public int size() {
return parent.size();
}
public void clear() {
parent.clear();
}
public boolean contains(Object entry) {
if (entry instanceof Map.Entry) {
Map.Entry e = (Map.Entry) entry;
Entry match = parent.getEntry(e.getKey());
return (match != null && match.equals(e));
}
return false;
}
public boolean remove(Object obj) {
if (obj instanceof Map.Entry == false) {
return false;
}
if (contains(obj) == false) {
return false;
}
Map.Entry entry = (Map.Entry) obj;
Object key = entry.getKey();
parent.remove(key);
return true;
}
public Iterator iterator() {
return parent.createEntrySetIterator();
}
}
/**
* EntrySet iterator.
*/
protected static class EntrySetIterator extends HashIterator {
protected EntrySetIterator(AbstractHashedMap parent) {
super(parent);
}
public Object next() {
return super.nextEntry();
}
}
//-----------------------------------------------------------------------
/**
* Gets the keySet view of the map.
* Changes made to the view affect this map.
* To simply iterate through the keys, use {@link #mapIterator()}.
*
* @return the keySet view
*/
public Set keySet() {
if (keySet == null) {
keySet = new KeySet(this);
}
return keySet;
}
/**
* Creates a key set iterator.
* Subclasses can override this to return iterators with different properties.
*
* @return the keySet iterator
*/
protected Iterator createKeySetIterator() {
if (size() == 0) {
return EmptyIterator.INSTANCE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -