软引用对象,在响应内存需要时,由垃圾回收器决定是否清除此对象。软引用对象最常用于实现内存敏感的缓存
软可到达对象的所有软引用都要保证在虚拟机抛出 OutOfMemoryError
之前已经被清除。
只要软引用的指示对象是强可到达对象,即正在实际使用的对象,就不会清除软引用
public class SoftHashMap<K, V> extends AbstractMap<K, V> implements Map<K, V> {
private static final int DEFAULT_INITIAL_CAPACITY = 16;
private static final int MAXIMUM_CAPACITY = 1 << 30;
private Entry[] table;
private final ReferenceQueue<K> queue = new ReferenceQueue<K>();
private static final Object NULL_KEY = new Object();
private int size;
public SoftHashMap() {
table = new Entry[DEFAULT_INITIAL_CAPACITY];
}
/**
* @param key
* @param value
* @return
*/
@SuppressWarnings("unchecked")
public V put(K key, V value) {
Entry[] tab = getTable();
Entry temp;
for (int j = 0; j < tab.length; j++) {
temp = tab[j];
if (temp == null) continue;
V oldKey = (V) temp.getKey();
if (key == oldKey) {
temp.setValue(value);
return (V) temp.getValue();
}
temp = null;
}
tab[size] = new Entry<K, V>(key, value, queue);
if (++size >= table.length) resize(table.length << 1);
return value;
}
/**
* @param newCapacity
*/
void resize(int newCapacity) {
Entry[] newTable = new Entry[newCapacity];
System.arraycopy(table, 0, newTable, 0, newTable.length);
table = newTable;
}
/**
* @param h
* @param length
* @return
*/
static int indexFor(int h, int length) {
return h & (length - 1);
}
/**
* @param key
* @return
*/
private int hash(Object key) {
return key.hashCode() & table.length;
}
/**
* @return
*/
private Entry[] getTable() {
expungeStaleEntries();
return table;
}
/**
*
*/
private void expungeStaleEntries() {
Entry<K, V> e;
while ((e = (Entry<K, V>) queue.poll()) != null) {
e = null;
size--;
}
}
/**
* @param key
* @return
*/
private static Object maskNull(Object key) {
return (key == null ? NULL_KEY : key);
}
/**
* @return
*/
public Set<java.util.Map.Entry<K, V>> entrySet() {
expungeStaleEntries();
Set<Map.Entry<K, V>> entrys = new HashSet<Map.Entry<K, V>>();
for (int i = 0; i < table.length; i++) {
if (table[i] == null) continue;
entrys.add(table[i]);
}
return entrys;
}
public String toString(){
return entrySet().toString();
}
private static class Entry<K, V> extends SoftReference<K> implements Map.Entry<K, V> {
private V value;
public Entry(K k, V v, ReferenceQueue queue) {
super(k, queue);
this.value = v;
}
public K getKey() {
return super.get();
}
public V getValue() {
return value;
}
public V setValue(V value) {
V oldvalue = value;
this.value = value;
return oldvalue;
}
public boolean equals(Object o) {
if (!(o instanceof Map.Entry)) return false;
Map.Entry e = (Map.Entry) o;
Object k1 = getKey();
Object k2 = e.getKey();
if (k1 == k2 || (k1 != null && k1.equals(k2))) {
Object v1 = getValue();
Object v2 = e.getValue();
if (v1 == v2 || (v1 != null && v1.equals(v2))) return true;
}
return false;
}
public int hashCode() {
Object k = getKey();
Object v = getValue();
return ((k == null ? 0 : k.hashCode()) ^ (v == null ? 0 : v.hashCode()));
}
public String toString() {
return getKey() + "=" + getValue();
}
}
public static void main(String[] args) throws Exception {
SoftHashMap<Object, Object> softHashMap = new SoftHashMap<Object, Object>();
Object key1 = new String("asdfasdf"); // 堆中的对象是可以被垃圾回收的,而栈中基本变量,引用变量,是在跳出所在的语句块时!
// 基本类型变量或对象变量所在栈内存被系统自动释放!并且内存空间能够立即被释放!
// Object key1 = "sadfasdf";
Object value1 = "B";
Object key2 = "D"; // 栈变量是不会被垃圾回收器收集的
Object value2 = "B";
Object key3 = "C";
Object value3 = "B";
softHashMap.put(key1, value1);
softHashMap.put(key2, value2);
softHashMap.put(key3, value3);
softHashMap.put(key3, "asdfadfasd");
key3 = null;
// key2 = null;
// key1 = null;
System.gc();
Thread.sleep(1000);
Set<Map.Entry<Object, Object>> set = softHashMap.entrySet();
for (Map.Entry<Object, Object> entry : set) {
System.out.println("===" + entry.getValue());
}
}
}