Java Tutorial/Collections/Reference
An implementation of Set that manages a map of soft references to the set values.
<source lang="java">
/*
* JBoss, Home of Professional Open Source * Copyright 2005, JBoss Inc., and individual contributors as indicated * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */
import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.lang.reflect.Array; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Set; /**
* An implementation of Set that manages a map of soft references to the set * values. The map is keyed by the value hashCode and so this is only useful for * value whose hashCode is a valid identity representation (String, primative * wrappers, etc). * * @author Scott.Stark@jboss.org * @version $Revision: 2787 $ */
@SuppressWarnings("unchecked") public class SoftSet implements Set {
private HashMap map = new HashMap(); /** The queue of garbage collected soft references */ private ReferenceQueue gcqueue = new ReferenceQueue(); static class ComparableSoftReference extends SoftReference { private Integer key; ComparableSoftReference(Integer key, Object o, ReferenceQueue q) { super(o, q); this.key = key; } Integer getKey() { return key; } } static class ComparableSoftReferenceIterator implements Iterator { Iterator theIter; ComparableSoftReferenceIterator(Iterator theIter) { this.theIter = theIter; } public boolean hasNext() { return theIter.hasNext(); } public Object next() { ComparableSoftReference csr = (ComparableSoftReference) theIter.next(); return csr.get(); } public void remove() { theIter.remove(); } } /** * */ public SoftSet() { } public int size() { processQueue(); return map.size(); } public boolean isEmpty() { processQueue(); return map.isEmpty(); } public boolean contains(Object o) { processQueue(); Integer key = new Integer(o.hashCode()); boolean contains = map.containsKey(key); return contains; } public Iterator iterator() { processQueue(); Iterator theIter = map.values().iterator(); return new ComparableSoftReferenceIterator(theIter); } public Object[] toArray() { processQueue(); return toArray(new Object[0]); } public Object[] toArray(Object[] a) { processQueue(); int size = map.size(); Object[] array = {}; if (a.length >= size) array = a; Iterator iter = map.values().iterator(); int index = 0; while (iter.hasNext()) { ComparableSoftReference csr = (ComparableSoftReference) iter.next(); Object value = csr.get(); // Create the correct array type if (array.length == 0) { if (value == null) { index++; continue; } Array.newInstance(value.getClass(), size); } array[index] = value; index++; } return array; } public boolean add(Object o) { processQueue(); Integer key = new Integer(o.hashCode()); ComparableSoftReference sr = new ComparableSoftReference(key, o, gcqueue); return map.put(key, sr) == null; } public boolean remove(Object o) { processQueue(); Integer key = new Integer(o.hashCode()); return map.remove(key) != null; } public boolean containsAll(Collection c) { processQueue(); Iterator iter = c.iterator(); boolean contains = true; while (iter.hasNext()) { Object value = iter.next(); Integer key = new Integer(value.hashCode()); contains &= map.containsKey(key); } return contains; } public boolean addAll(Collection c) { processQueue(); Iterator iter = c.iterator(); boolean added = false; while (iter.hasNext()) { Object value = iter.next(); Integer key = new Integer(value.hashCode()); ComparableSoftReference sr = new ComparableSoftReference(key, value, gcqueue); added |= map.put(key, sr) == null; } return added; } public boolean retainAll(Collection c) { Iterator iter = iterator(); boolean removed = false; while (iter.hasNext()) { Object value = iter.next(); if (c.contains(value) == false) { iter.remove(); removed = true; } } return removed; } public boolean removeAll(Collection c) { processQueue(); Iterator iter = c.iterator(); boolean removed = false; while (iter.hasNext()) { Object value = iter.next(); removed |= remove(value); } return removed; } public void clear() { while (gcqueue.poll() != null) ; map.clear(); } public boolean equals(Object o) { return map.equals(o); } public int hashCode() { return map.hashCode(); } /** * Iterate through the gcqueue for for any cleared reference, remove the * associated value from the underlying set. */ private void processQueue() { ComparableSoftReference cr; while ((cr = (ComparableSoftReference) gcqueue.poll()) != null) { map.remove(cr.getKey()); } }
}</source>
Cache based on SoftReference
<source lang="java">
/* Copyright 2004 The Apache Software Foundation
* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */
// Revised from xmlbeans import java.util.HashMap; import java.lang.ref.SoftReference; /**
* @author Cezar Andrei (cezar.andrei at bea.ru) * Date: Apr 26, 2005 */
public class SoftCache {
private HashMap map = new HashMap(); public Object get(Object key) { SoftReference softRef = (SoftReference)map.get(key); if (softRef==null) return null; return softRef.get(); } public Object put(Object key, Object value) { SoftReference softRef = (SoftReference)map.put(key, new SoftReference(value)); if (softRef==null) return null; Object oldValue = softRef.get(); softRef.clear(); return oldValue; } public Object remove(Object key) { SoftReference softRef = (SoftReference)map.remove(key); if (softRef==null) return null; Object oldValue = softRef.get(); softRef.clear(); return oldValue; }
}</source>
WeakReference list uses java.lang.ref.WeakReferences to store its contents.
<source lang="java">
/**
* * JFreeReport : a free Java reporting library * * * Project Info: http://reporting.pentaho.org/ * * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors. * * This library is free software; you can redistribute it and/or modify it under the terms * of the GNU Lesser General Public License as published by the Free Software Foundation; * either version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307, USA. * * [Java is a trademark or registered trademark of Sun Microsystems, Inc. * in the United States and other countries.] * * ------------ * WeakReferenceList.java * ------------ * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors. */
import java.io.IOException; import java.io.ObjectInputStream; import java.io.Serializable; import java.lang.ref.Reference; import java.lang.ref.WeakReference; /**
* The WeakReference list usesjava.lang.ref.WeakReference
s to store its contents. In contrast to the * WeakHashtable, this list knows how to restore missing content, so that garbage collected elements can be restored * when they are accessed. * <p/> * By default this list can contain 25 elements, where the first element is stored using a strong reference, which is * not garbage collected. * <p/> * Restoring the elements is not implemented, concrete implementations will have to override the *restoreChild(int)
method. ThegetMaxChildCount
method defines the maxmimum number of * children in the list. When more thanmaxChildCount
elements are contained in this list, add will always * return false to indicate that adding the element failed. * <p/> * To customize the list, override createReference to create a different kind of reference. * <p/> * This list is able to add or replace elements, but inserting or removing of elements is not possible. * * @author Thomas Morgner */
public abstract class WeakReferenceList implements Serializable, Cloneable {
/** * The master element. */ private Object master; /** * Storage for the references. */ private transient Reference[] childs; /** * The current number of elements. */ private int size; /** * The maximum number of elements. */ private final int maxChilds; /** * Creates a new weak reference list. The storage of the list is limited to getMaxChildCount() elements. * * @param maxChildCount the maximum number of elements. */ protected WeakReferenceList(final int maxChildCount) { this.maxChilds = maxChildCount; this.childs = new Reference[maxChildCount - 1]; } /** * Returns the maximum number of children in this list. * * @return the maximum number of elements in this list. */ protected final int getMaxChildCount() { return maxChilds; } /** * Returns the master element of this list. The master element is the element stored by a strong reference and cannot * be garbage collected. * * @return the master element */ protected Object getMaster() { return master; } /** * Attempts to restore the child stored on the given index. * * @param index the index. * @return null if the child could not be restored or the restored child. */ protected abstract Object restoreChild(int index); /** * Returns the child stored at the given index. If the child has been garbage collected, it gets restored using the * restoreChild function. * * @param index the index. * @return the object. */ public Object get(final int index) { if (isMaster(index)) { return master; } else { final Reference ref = childs[getChildPos(index)]; if (ref == null) { throw new IllegalStateException("State: " + index); } Object ob = ref.get(); if (ob == null) { ob = restoreChild(index); childs[getChildPos(index)] = createReference(ob); } return ob; } } /** * Replaces the child stored at the given index with the new child which can be null. * * @param report the object. * @param index the index. */ public void set(final Object report, final int index) { if (isMaster(index)) { master = report; } else { childs[getChildPos(index)] = createReference(report); } } /** * Creates a new reference for the given object. * * @param o the object. * @return a WeakReference for the object o without any ReferenceQueue attached. */ private Reference createReference(final Object o) { return new WeakReference(o); } /** * Adds the element to the list. If the maximum size of the list is exceeded, this function returns false to indicate * that adding failed. * * @param rs the object. * @return true, if the object was successfully added to the list, false otherwise */ public boolean add(final Object rs) { if (size == 0) { master = rs; size = 1; return true; } else { if (size < getMaxChildCount()) { childs[size - 1] = createReference(rs); size++; return true; } else { // was not able to add this to this list, maximum number of entries reached. return false; } } } /** * Returns true, if the given index denotes a master index of this list. * * @param index the index. * @return true if the index is a master index. */ protected boolean isMaster(final int index) { return index % getMaxChildCount() == 0; } /** * Returns the internal storage position for the child. * * @param index the index. * @return the internal storage index. */ protected int getChildPos(final int index) { return index % getMaxChildCount() - 1; } /** * Returns the size of the list. * * @return the size. */ public int getSize() { return size; } /** * Serialisation support. The transient child elements were not saved. * * @param in the input stream. * @throws IOException if there is an I/O error. * @throws ClassNotFoundException if a serialized class is not defined on this system. */ private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); childs = new Reference[getMaxChildCount() - 1]; for (int i = 0; i < childs.length; i++) { childs[i] = createReference(null); } } /** * Creates and returns a copy of this object. The precise meaning of "copy" may depend on the class of the object.* The general intent is that, for any object x, the expression:
** will be true, and that the expression:* x.clone() != x
** will be true, but these are not absolute requirements. While it is typically the case that:* x.clone().getClass() == x.getClass()
** x.clone().equals(x)
* will be true, this is not an absolute requirement. * <p/> * By convention, the returned object should be obtained by calling super.clone. If a class and all of its * superclasses (except Object) obey this convention, it will be the case that x.clone().getClass() == * x.getClass(). * <p/> * By convention, the object returned by this method should be independent of this object (which is being cloned). To * achieve this independence, it may be necessary to modify one or more fields of the object returned by * super.clone before returning it. Typically, this means copying any mutable objects that comprise the * internal "deep structure" of the object being cloned and replacing the references to these objects with references * to the copies. If a class contains only primitive fields or references to immutable objects, then it is usually * the case that no fields in the object returned by super.clone need to be modified. * <p/> * The method clone for class Object performs a specific cloning operation. First, if the class of * this object does not implement the interface Cloneable, then a CloneNotSupportedException is * thrown. Note that all arrays are considered to implement the interface Cloneable. Otherwise, this method * creates a new instance of the class of this object and initializes all its fields with exactly the contents of the * corresponding fields of this object, as if by assignment; the contents of the fields are not themselves cloned. * Thus, this method performs a "shallow copy" of this object, not a "deep copy" operation. * <p/> * The class Object does not itself implement the interface Cloneable, so calling the clone * method on an object whose class is Object will result in throwing an exception at run time. * * @return a clone of this instance. * @throws CloneNotSupportedException if the object"s class does not support theCloneable
interface. * Subclasses that override theclone
method can also throw this * exception to indicate that an instance cannot be cloned. * @see Cloneable */ protected Object clone() throws CloneNotSupportedException { final WeakReferenceList list = (WeakReferenceList) super.clone(); list.childs = (Reference[]) childs.clone(); return list; }
}</source>