Java Tutorial/Collections/Reference

Материал из Java эксперт
Версия от 05:04, 1 июня 2010; Admin (обсуждение | вклад) (1 версия)
(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к: навигация, поиск

An implementation of Set that manages a map of soft references to the set values.

/*
 * 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());
    }
  }
}





Cache based on SoftReference

/*   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;
    }
}





WeakReference list uses java.lang.ref.WeakReferences to store its contents.

/**
 * 
 * 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 uses <code>java.lang.ref.WeakReference</code>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
 * <code>restoreChild(int)</code> method. The <code>getMaxChildCount</code> method defines the maxmimum number of
 * children in the list. When more than <code>maxChildCount</code> 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 <tt>x</tt>, the expression: <blockquote>
   * <pre>
   * x.clone() != x</pre></blockquote>
   * will be true, and that the expression: <blockquote>
   * <pre>
   * x.clone().getClass() == x.getClass()</pre></blockquote>
   * will be <tt>true</tt>, but these are not absolute requirements. While it is typically the case that: <blockquote>
   * <pre>
   * x.clone().equals(x)</pre></blockquote>
   * will be <tt>true</tt>, this is not an absolute requirement.
   * <p/>
   * By convention, the returned object should be obtained by calling <tt>super.clone</tt>.  If a class and all of its
   * superclasses (except <tt>Object</tt>) obey this convention, it will be the case that <tt>x.clone().getClass() ==
   * x.getClass()</tt>.
   * <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
   * <tt>super.clone</tt> 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 <tt>super.clone</tt> need to be modified.
   * <p/>
   * The method <tt>clone</tt> for class <tt>Object</tt> performs a specific cloning operation. First, if the class of
   * this object does not implement the interface <tt>Cloneable</tt>, then a <tt>CloneNotSupportedException</tt> is
   * thrown. Note that all arrays are considered to implement the interface <tt>Cloneable</tt>. 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 <tt>Object</tt> does not itself implement the interface <tt>Cloneable</tt>, so calling the <tt>clone</tt>
   * method on an object whose class is <tt>Object</tt> 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 the <code>Cloneable</code> interface.
   *                                    Subclasses that override the <code>clone</code> 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;
  }
}