工作中需要用到弱引用的集合和列表.网上搜集了点资料,自己整理下发出来备份.
WeakHashSet是模仿HashSet的实现方式,使用WeakHashMap实现的.
WeakArrayList是修改自org.arakhne.util.ref下的WeakArrayList.
SpeedyKit.copyOf方法是1.6中Arrays下同名方法.我用的1.5,需要把此方法拷贝出来.
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
import java.util.WeakHashMap;
/**
* 参照{@link java.util.HashSet}实现的WeakHashSet.详细介绍参看{@link java.util.Set}和
* {@link java.util.WeakHashMap}功能<br>
*
*/
public class WeakHashSet<E> extends AbstractSet<E> implements Set<E> {
private transient WeakHashMap<E, Object> map;
private static final Object PRESENT = new Object();
public WeakHashSet() {
this.map = new WeakHashMap<E, Object>();
}
public WeakHashSet(Collection<? extends E> c) {
this.map = new WeakHashMap<E, Object>(Math.max(
(int) (c.size() / .75f) + 1, 16));
this.addAll(c);
}
public WeakHashSet(int initialCapacity, float loadFactor) {
this.map = new WeakHashMap<E, Object>(initialCapacity, loadFactor);
}
public WeakHashSet(int initialCapacity) {
this.map = new WeakHashMap<E, Object>(initialCapacity);
}
public Iterator<E> iterator() {
return this.map.keySet().iterator();
}
public int size() {
return this.map.size();
}
@Override
public boolean isEmpty() {
return this.map.isEmpty();
}
@Override
public boolean contains(Object o) {
return this.map.containsKey(o);
}
@Override
public boolean add(E o) {
return this.map.put(o, WeakHashSet.PRESENT) == null;
}
@Override
public boolean remove(Object o) {
return this.map.remove(o) == WeakHashSet.PRESENT;
}
@Override
public void clear() {
this.map.clear();
}
}
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.AbstractList;
import java.util.Collection;
/**
* 弱引用列表 <br>
*
*/
public class WeakArrayList<T> extends AbstractList<T> {
private static final long serialVersionUID = 2601162363164961860L;
private static final Object NULL_VALUE = new Object();
private final transient ReferenceQueue<T> queue;
private Object[] data;
private int size;
private boolean enquedElement;
@SuppressWarnings("unchecked")
private static <T> T maskNull(T value) {
return (T) (value == null ? WeakArrayList.NULL_VALUE : value);
}
private static <T> T unmaskNull(T value) {
return (value == WeakArrayList.NULL_VALUE ? null : value);
}
public WeakArrayList(int initialCapacity) {
this.queue = new ReferenceQueue<T>();
this.enquedElement = false;
if (initialCapacity < 0) {
throw new IllegalArgumentException("Illegal Capacity: "
+ initialCapacity);
}
this.data = new Object[initialCapacity];
this.size = 0;
}
public WeakArrayList() {
this(10);
}
public WeakArrayList(Collection<? extends T> c) {
this.queue = new ReferenceQueue<T>();
this.enquedElement = false;
this.data = new Object[c.size()];
this.size = this.data.length;
int i = 0;
for (T t : c) {
this.data[i] = this.createRef(t);
++i;
}
}
@SuppressWarnings("unchecked")
public String toString() {
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < this.size; ++i) {
Object obj;
Reference<T> ref = (Reference<T>) this.data[i];
if (this.data[i] == null) {
obj = null;
} else {
obj = ref.get();
}
buffer.append('{');
buffer.append(obj == null ? null : obj.toString());
buffer.append('}');
}
return buffer.toString();
}
@SuppressWarnings("unchecked")
private Reference<T> createRef(T obj) {
return new WeakReference(WeakArrayList.maskNull(obj), this.queue);
}
public void ensureCapacity(int minCapacity) {
this.modCount += 1;
int oldCapacity = this.data.length;
if (minCapacity > oldCapacity) {
Object[] oldData = this.data;
int newCapacity = oldCapacity * 3 / 2 + 1;
if (newCapacity < minCapacity) {
newCapacity = minCapacity;
}
this.data = SpeedyKit.copyOf(oldData, newCapacity);
}
}
public void trimToSize() {
this.modCount += 1;
int oldCapacity = this.data.length;
if (this.size < oldCapacity) {
this.data = SpeedyKit.copyOf(this.data, this.size);
}
}
@SuppressWarnings("unchecked")
public int expurge() {
int j;
while (this.queue.poll() != null) {
this.enquedElement = true;
}
if (this.enquedElement) {
j = 0;
for (int i = 0; i < this.size; ++i) {
Reference<T> ref = (Reference<T>) this.data[i];
if (ref == null || ref.isEnqueued() || ref.get() == null) {
if (ref != null) {
ref.clear();
}
this.data[i] = null;
} else {
if (i != j) {
this.data[j] = this.data[i];
this.data[i] = null;
}
++j;
}
}
this.enquedElement = false;
} else {
j = this.size;
}
while (this.queue.poll() != null) {
this.enquedElement = true;
}
this.size = j;
return this.size;
}
protected void assertRange(int index, boolean allowLast) {
int csize = this.expurge();
if (index < 0) {
throw new IndexOutOfBoundsException("invalid negative value: "
+ Integer.toString(index));
}
if (allowLast && index > csize) {
throw new IndexOutOfBoundsException("index>" + csize + ": "
+ Integer.toString(index));
}
if (!allowLast && index >= csize) {
throw new IndexOutOfBoundsException("index>=" + csize + ": "
+ Integer.toString(index));
}
}
public int size() {
return this.expurge();
}
@SuppressWarnings("unchecked")
public T get(int index) {
Object value;
do {
this.assertRange(index, false);
value = ((Reference<T>) this.data[index]).get();
} while (value == null);
return (T) WeakArrayList.unmaskNull(value);
}
@SuppressWarnings("unchecked")
public T set(int index, T element) {
Object oldValue;
Reference<T> ref;
do {
this.assertRange(index, false);
ref = (Reference<T>) this.data[index];
oldValue = ref.get();
} while (oldValue == null);
ref.clear();
this.data[index] = this.createRef(element);
this.modCount += 1;
return (T) WeakArrayList.unmaskNull(oldValue);
}
public void add(int index, T element) {
this.assertRange(index, true);
this.ensureCapacity(this.size + 1);
System.arraycopy(this.data, index, this.data, index + 1, this.size
- index);
this.data[index] = this.createRef(element);
this.size += 1;
this.modCount += 1;
}
@SuppressWarnings("unchecked")
public T remove(int index) {
Object oldValue;
Reference<T> ref;
do {
this.assertRange(index, false);
ref = (Reference<T>) this.data[index];
oldValue = ref.get();
} while (oldValue == null);
ref.clear();
System.arraycopy(this.data, index + 1, this.data, index, this.size
- index - 1);
this.data[(this.size - 1)] = null;
this.size -= 1;
this.modCount += 1;
return (T) WeakArrayList.unmaskNull(oldValue);
}
public static void main(String[] args) {
Object a = new Object();
WeakArrayList<Object> list = new WeakArrayList<Object>();
for (int i = 0; i < 100000; i++) {
list.add(a);
}
int size = list.size();
System.out.println(size);
a = null;
while (list.size() == size) {
System.gc();
}
System.out.println(list.size());
}
}