weakhashmap.java
来自「纯java操作系统jnode,安装简单和操作简单的个人使用的Java操作系统」· Java 代码 · 共 815 行 · 第 1/2 页
JAVA
815 行
/**
* Returns the value.
* @return the value
*/
public Object getValue() {
return value;
}
/**
* This changes the value. This change takes place in
* the underlying hash map.
* @param newVal the new value
* @return the old value
*/
public Object setValue(Object newVal) {
Object oldVal = value;
value = newVal;
return oldVal;
}
/**
* The hashCode as specified in the Entry interface.
* @return the hash code
*/
public int hashCode() {
return key.hashCode() ^ WeakHashMap.hashCode(value);
}
/**
* The equals method as specified in the Entry interface.
* @param o the object to compare to
* @return true iff o represents the same key/value pair
*/
public boolean equals(Object o) {
if (o instanceof Map.Entry) {
Map.Entry e = (Map.Entry) o;
return key.equals(e.getKey()) && WeakHashMap.equals(value, e.getValue());
}
return false;
}
public String toString() {
return key + "=" + value;
}
}
/**
* This returns the entry stored in this bucket, or null, if the
* bucket got cleared in the mean time.
* @return the Entry for this bucket, if it exists
*/
WeakEntry getEntry() {
final Object key = this.get();
if (key == null)
return null;
return new WeakEntry(key);
}
}
/**
* The entry set returned by <code>entrySet()</code>.
*/
private final WeakEntrySet theEntrySet;
/**
* The hash buckets. These are linked lists. Package visible for use in
* nested classes.
*/
WeakBucket[] buckets;
/**
* Creates a new weak hash map with default load factor and default
* capacity.
*/
public WeakHashMap() {
this(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR);
}
/**
* Creates a new weak hash map with default load factor and the given
* capacity.
* @param initialCapacity the initial capacity
* @throws IllegalArgumentException if initialCapacity is negative
*/
public WeakHashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
/**
* Creates a new weak hash map with the given initial capacity and
* load factor.
* @param initialCapacity the initial capacity.
* @param loadFactor the load factor (see class description of HashMap).
* @throws IllegalArgumentException if initialCapacity is negative, or
* loadFactor is non-positive
*/
public WeakHashMap(int initialCapacity, float loadFactor) {
// Check loadFactor for NaN as well.
if (initialCapacity < 0 || !(loadFactor > 0))
throw new IllegalArgumentException();
this.loadFactor = loadFactor;
threshold = (int) (initialCapacity * loadFactor);
theEntrySet = new WeakEntrySet();
queue = new ReferenceQueue();
buckets = new WeakBucket[initialCapacity];
}
/**
* Construct a new WeakHashMap with the same mappings as the given map.
* The WeakHashMap has a default load factor of 0.75.
*
* @param m the map to copy
* @throws NullPointerException if m is null
* @since 1.3
*/
public WeakHashMap(Map m) {
this(m.size(), DEFAULT_LOAD_FACTOR);
putAll(m);
}
/**
* Simply hashes a non-null Object to its array index.
* @param key the key to hash
* @return its slot number
*/
private int hash(Object key) {
return Math.abs(key.hashCode() % buckets.length);
}
/**
* Cleans the reference queue. This will poll all references (which
* are WeakBuckets) from the queue and remove them from this map.
* This will not change modCount, even if it modifies the map. The
* iterators have to make sure that nothing bad happens. <br>
*
* Currently the iterator maintains a strong reference to the key, so
* that is no problem.
*/
// Package visible for use by nested classes.
void cleanQueue() {
Object bucket = queue.poll();
while (bucket != null) {
internalRemove((WeakBucket) bucket);
bucket = queue.poll();
}
}
/**
* Rehashes this hashtable. This will be called by the
* <code>add()</code> method if the size grows beyond the threshold.
* It will grow the bucket size at least by factor two and allocates
* new buckets.
*/
private void rehash() {
WeakBucket[] oldBuckets = buckets;
int newsize = buckets.length * 2 + 1; // XXX should be prime.
threshold = (int) (newsize * loadFactor);
buckets = new WeakBucket[newsize];
// Now we have to insert the buckets again.
for (int i = 0; i < oldBuckets.length; i++) {
WeakBucket bucket = oldBuckets[i];
WeakBucket nextBucket;
while (bucket != null) {
nextBucket = bucket.next;
Object key = bucket.get();
if (key == null) {
// This bucket should be removed; it is probably
// already on the reference queue. We don't insert it
// at all, and mark it as cleared.
bucket.slot = -1;
size--;
} else {
// Add this bucket to its new slot.
int slot = hash(key);
bucket.slot = slot;
bucket.next = buckets[slot];
buckets[slot] = bucket;
}
bucket = nextBucket;
}
}
}
/**
* Finds the entry corresponding to key. Since it returns an Entry
* it will also prevent the key from being removed under us.
* @param key the key, may be null
* @return The WeakBucket.WeakEntry or null, if the key wasn't found.
*/
private WeakBucket.WeakEntry internalGet(Object key) {
if (key == null)
key = NULL_KEY;
int slot = hash(key);
WeakBucket bucket = buckets[slot];
while (bucket != null) {
WeakBucket.WeakEntry entry = bucket.getEntry();
if (entry != null && key.equals(entry.key))
return entry;
bucket = bucket.next;
}
return null;
}
/**
* Adds a new key/value pair to the hash map.
* @param key the key. This mustn't exists in the map. It may be null.
* @param value the value.
*/
private void internalAdd(Object key, Object value) {
if (key == null)
key = NULL_KEY;
int slot = hash(key);
WeakBucket bucket = new WeakBucket(key, queue, value, slot);
bucket.next = buckets[slot];
buckets[slot] = bucket;
size++;
}
/**
* Removes a bucket from this hash map, if it wasn't removed before
* (e.g. one time through rehashing and one time through reference queue).
* Package visible for use in nested classes.
*
* @param bucket the bucket to remove.
*/
void internalRemove(WeakBucket bucket) {
int slot = bucket.slot;
if (slot == -1)
// This bucket was already removed.
return;
// Mark the bucket as removed. This is necessary, since the
// bucket may be enqueued later by the garbage collection, and
// internalRemove will be called a second time.
bucket.slot = -1;
if (buckets[slot] == bucket)
buckets[slot] = bucket.next;
else {
WeakBucket prev = buckets[slot];
/* This may throw a NullPointerException. It shouldn't but if
* a race condition occurred (two threads removing the same
* bucket at the same time) it may happen. <br>
* But with race condition many much worse things may happen
* anyway.
*/
while (prev.next != bucket)
prev = prev.next;
prev.next = bucket.next;
}
size--;
}
/**
* Returns the size of this hash map. Note that the size() may shrink
* spontaneously, if the some of the keys were only weakly reachable.
* @return the number of entries in this hash map.
*/
public int size() {
cleanQueue();
return size;
}
/**
* Tells if the map is empty. Note that the result may change
* spontanously, if all of the keys were only weakly reachable.
* @return true, iff the map is empty.
*/
public boolean isEmpty() {
cleanQueue();
return size == 0;
}
/**
* Tells if the map contains the given key. Note that the result
* may change spontanously, if the key was only weakly
* reachable.
* @param key the key to look for
* @return true, iff the map contains an entry for the given key.
*/
public boolean containsKey(Object key) {
cleanQueue();
return internalGet(key) != null;
}
/**
* Gets the value the key is mapped to.
* @return the value the key was mapped to. It returns null if
* the key wasn't in this map, or if the mapped value was
* explicitly set to null.
*/
public Object get(Object key) {
cleanQueue();
WeakBucket.WeakEntry entry = internalGet(key);
return entry == null ? null : entry.getValue();
}
/**
* Adds a new key/value mapping to this map.
* @param key the key, may be null
* @param value the value, may be null
* @return the value the key was mapped to previously. It returns
* null if the key wasn't in this map, or if the mapped value
* was explicitly set to null.
*/
public Object put(Object key, Object value) {
cleanQueue();
WeakBucket.WeakEntry entry = internalGet(key);
if (entry != null)
return entry.setValue(value);
modCount++;
if (size >= threshold)
rehash();
internalAdd(key, value);
return null;
}
/**
* Removes the key and the corresponding value from this map.
* @param key the key. This may be null.
* @return the value the key was mapped to previously. It returns
* null if the key wasn't in this map, or if the mapped value was
* explicitly set to null.
*/
public Object remove(Object key) {
cleanQueue();
WeakBucket.WeakEntry entry = internalGet(key);
if (entry == null)
return null;
modCount++;
internalRemove(entry.getBucket());
return entry.getValue();
}
/**
* Returns a set representation of the entries in this map. This
* set will not have strong references to the keys, so they can be
* silently removed. The returned set has therefore the same
* strange behaviour (shrinking size(), disappearing entries) as
* this weak hash map.
* @return a set representation of the entries.
*/
public Set entrySet() {
cleanQueue();
return theEntrySet;
}
/**
* Clears all entries from this map.
*/
public void clear() {
super.clear();
}
/**
* Returns true if the map contains at least one key which points to
* the specified object as a value. Note that the result
* may change spontanously, if its key was only weakly reachable.
* @param value the value to search for
* @return true if it is found in the set.
*/
public boolean containsValue(Object value) {
cleanQueue();
return super.containsValue(value);
}
/**
* Returns a set representation of the keys in this map. This
* set will not have strong references to the keys, so they can be
* silently removed. The returned set has therefore the same
* strange behaviour (shrinking size(), disappearing entries) as
* this weak hash map.
* @return a set representation of the keys.
*/
public Set keySet() {
cleanQueue();
return super.keySet();
}
/**
* Puts all of the mappings from the given map into this one. If the
* key already exists in this map, its value is replaced.
* @param m the map to copy in
*/
public void putAll(Map m) {
super.putAll(m);
}
/**
* Returns a collection representation of the values in this map. This
* collection will not have strong references to the keys, so mappings
* can be silently removed. The returned collection has therefore the same
* strange behaviour (shrinking size(), disappearing entries) as
* this weak hash map.
* @return a collection representation of the values.
*/
public Collection values() {
cleanQueue();
return super.values();
}
} // class WeakHashMap
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?