home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / util / AbstractMap.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  17.4 KB  |  507 lines

  1. /*
  2.  * @(#)AbstractMap.java    1.12 98/03/18
  3.  *
  4.  * Copyright 1997, 1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.util;
  16. import java.util.Map.Entry;
  17.  
  18. /**
  19.  * This class provides a skeletal implementation of the Map interface,
  20.  * to minimize the effort required to implement this interface.
  21.  * <p>
  22.  * To implement an unmodifiable Map, the programmer needs only to extend this
  23.  * class and provide an implementation for the entries() method, which returns
  24.  * a Set-view of the Map's mappings.  Typically, the returned Set will, in
  25.  * turn, be implemented atop AbstractSet.  This Set should not support the add
  26.  * or remove methods, and its Iterator should not support the remove method.
  27.  * <p>
  28.  
  29.  * To implement a modifiable Map, the programmer must additionally override
  30.  * this class's put method (which otherwise throws an
  31.  * UnsupportedOperationException), and the Iterator returned by
  32.  * entries().iterator() must additionally implement its remove method.
  33.  
  34.  * <p>
  35.  * The programmer should generally provide a void (no argument) and
  36.  * Map constructor, as per the recommendation in the Map interface
  37.  * specification.
  38.  * <p>
  39.  * The documentation for each non-abstract methods in this class describes its
  40.  * implementation in detail.  Each of these methods may be overridden if
  41.  * the Map being implemented admits a more efficient implementation.
  42.  *
  43.  * @author  Josh Bloch
  44.  * @version 1.12 03/18/98
  45.  * @see Map
  46.  * @see Collection
  47.  * @since JDK1.2
  48.  */
  49.  
  50. public abstract class AbstractMap implements Map {
  51.     // Query Operations
  52.  
  53.     /**
  54.      * Returns the number of key-value mappings in this Map.
  55.      * <p>
  56.      * This implementation returns <code>entries().size()</code>.
  57.      */
  58.     public int size() {
  59.     return entries().size();
  60.     }
  61.  
  62.     /**
  63.      * Returns true if this Map contains no key-value mappings.
  64.      * <p>
  65.      * This implementation returns <code>size() == 0</code>.
  66.      */
  67.     public boolean isEmpty() {
  68.     return size() == 0;
  69.     }
  70.  
  71.     /**
  72.      * Returns true if this Map maps one or more keys to this value.
  73.      * More formally, returns true if and only if this Map contains at
  74.      * least one mapping to a value <code>v</code> such that
  75.      * <code>(value==null ? v==null : value.equals(v))</code>.
  76.      * This operation will probably require time linear in the Map size for
  77.      * most implementations of Map.
  78.      * <p>
  79.      * This implementation iterates over entries() searching for an Entry
  80.      * with the specified value.  If such an Entry is found, true is
  81.      * returned.  If the iteration terminates without finding such an
  82.      * Entry, false is returned.  Note that this implementation requires
  83.      * linear time in the size of the Map.
  84.      *
  85.      * @param value value whose presence in this Map is to be tested.
  86.      */
  87.     public boolean containsValue(Object value) {
  88.     Iterator i = entries().iterator();
  89.     if (value==null) {
  90.         while (i.hasNext()) {
  91.         Entry e = (Entry) i.next();
  92.         if (e.getValue()==null)
  93.             return true;
  94.         }
  95.     } else {
  96.         while (i.hasNext()) {
  97.         Entry e = (Entry) i.next();
  98.         if (value.equals(e.getValue()))
  99.             return true;
  100.         }
  101.     }
  102.     return false;
  103.     }
  104.  
  105.     /**
  106.      * Returns true if this Map contains a mapping for the specified key.
  107.      * <p>
  108.      * This implementation iterates over entries() searching for an Entry
  109.      * with the specified key.  If such an Entry is found, true is
  110.      * returned.  If the iteration terminates without finding such an
  111.      * Entry, false is returned.  Note that this implementation requires
  112.      * linear time in the size of the Map; many implementations will
  113.      * override this method.
  114.      *
  115.      * @param key key whose presence in this Map is to be tested.
  116.      * @exception ClassCastException key is of an inappropriate type for
  117.      *           this Map.
  118.      * @exception NullPointerException key is null and this Map does not
  119.      *          not permit null keys.
  120.      */
  121.     public boolean containsKey(Object key) {
  122.     Iterator i = entries().iterator();
  123.     if (key==null) {
  124.         while (i.hasNext()) {
  125.         Entry e = (Entry) i.next();
  126.         if (e.getKey()==null)
  127.             return true;
  128.         }
  129.     } else {
  130.         while (i.hasNext()) {
  131.         Entry e = (Entry) i.next();
  132.         if (key.equals(e.getKey()))
  133.             return true;
  134.         }
  135.     }
  136.     return false;
  137.     }
  138.  
  139.     /**
  140.      * Returns the value to which this Map maps the specified key.
  141.      * Returns null if the Map contains no mapping for this key.  A return
  142.      * value of null does not <em>necessarily</em> indicate that the Map
  143.      * contains no mapping for the key; it's also possible that the Map
  144.      * explicitly maps the key to null.  The containsKey operation may be
  145.      * used to distinguish these two cases. 
  146.      * <p>
  147.      * This implementation iterates over entries() searching for an Entry
  148.      * with the specified key.  If such an Entry is found, the Entry's
  149.      * value is returned.  If the iteration terminates without finding such
  150.      * an Entry, null is returned.  Note that this implementation requires
  151.      * linear time in the size of the Map; many implementations will
  152.      * override this method.
  153.      *
  154.      * @param key key whose associated value is to be returned.
  155.      * @exception ClassCastException key is of an inappropriate type for
  156.      *           this Map.
  157.      * @exception NullPointerException key is null and this Map does not
  158.      *          not permit null keys.
  159.      * @see #containsKey(Object)
  160.      */
  161.     public Object get(Object key) {
  162.     Iterator i = entries().iterator();
  163.     if (key==null) {
  164.         while (i.hasNext()) {
  165.         Entry e = (Entry) i.next();
  166.         if (e.getKey()==null)
  167.             return e.getValue();
  168.         }
  169.     } else {
  170.         while (i.hasNext()) {
  171.         Entry e = (Entry) i.next();
  172.         if (key.equals(e.getKey()))
  173.             return e.getValue();
  174.         }
  175.     }
  176.     return null;
  177.     }
  178.  
  179.  
  180.     // Modification Operations
  181.  
  182.     /**
  183.      * Associates the specified value with the specified key in this Map
  184.      * (optional operation).  If the Map previously contained a mapping for
  185.      * this key, the old value is replaced.
  186.      * <p>
  187.      * This implementation always throws an UnsupportedOperationException.
  188.      *
  189.      * @param key key with which the specified value is to be associated.
  190.      * @param value value to be associated with the specified key.
  191.      * @return previous value associated with specified key, or null if there
  192.      *           was no mapping for key.  (A null return can also indicate that
  193.      *           the Map previously associated null with the specified key,
  194.      *           if the implementation supports null values.)
  195.      * @exception UnsupportedOperationException put operation is not
  196.      *              supported by this Map.
  197.      * @exception ClassCastException class of the specified key or value
  198.      *               prevents it from being stored in this Map.
  199.      * @exception IllegalArgumentException some aspect of this key or value
  200.      *              prevents it from being stored in this Map.
  201.      * @exception NullPointerException this Map does not permit null keys
  202.      *          or values, and the specified key or value is null.
  203.      */
  204.     public Object put(Object key, Object value) {
  205.     throw new UnsupportedOperationException();
  206.     }
  207.  
  208.     /**
  209.      * Removes the mapping for this key from this Map if present (optional
  210.      * operation).
  211.      * <p>
  212.      * This implementation iterates over entries() searching for an Entry
  213.      * with the specified key.  If such an Entry is found, its value is
  214.      * obtained with its getValue operation, the Entry is is removed from the
  215.      * Collection (and the backing Map) with the Iterator's remove
  216.      * operation, and the saved value is returned.  If the iteration
  217.      * terminates without finding such an Entry, null is returned.  Note that
  218.      * this implementation requires linear time in the size of the Map;
  219.      * many implementations will override this method.
  220.      *
  221.      * @param key key whose mapping is to be removed from the Map.
  222.      * @return previous value associated with specified key, or null if there
  223.      *           was no entry for key.  (A null return can also indicate that
  224.      *           the Map previously associated null with the specified key,
  225.      *           if the implementation supports null values.)
  226.      * @exception UnsupportedOperationException remove is not supported
  227.      *           by this Map.
  228.      */
  229.     public Object remove(Object key) {
  230.     Iterator i = entries().iterator();
  231.     Entry correctEntry = null;
  232.     if (key==null) {
  233.         while (correctEntry==null && i.hasNext()) {
  234.         Entry e = (Entry) i.next();
  235.         if (e.getKey()==null)
  236.             correctEntry = e;
  237.         }
  238.     } else {
  239.         while (correctEntry==null && i.hasNext()) {
  240.         Entry e = (Entry) i.next();
  241.         if (key.equals(e.getKey()))
  242.             correctEntry = e;
  243.         }
  244.     }
  245.  
  246.     Object oldValue = null;
  247.     if (correctEntry !=null) {
  248.         oldValue = correctEntry.getValue();
  249.         i.remove();
  250.     }
  251.     return oldValue;
  252.     }
  253.  
  254.  
  255.     // Bulk Operations
  256.  
  257.     /**
  258.      * Copies all of the mappings from the specified Map to this Map
  259.      * (optional operation).  These mappings will replace any mappings that
  260.      * this Map had for any of the keys currently in the specified Map.
  261.      * <p>
  262.      * This implementation iterates over the specified Map's entries()
  263.      * Collection, and calls this Map's put operation once for each 
  264.      * Entry returned by the iteration.
  265.      *
  266.      * @param t Mappings to be stored in this Map.
  267.      * @exception UnsupportedOperationException putAll is not supported
  268.      *           by this Map.
  269.      * @exception ClassCastException class of a key or value in the specified
  270.      *               Map prevents it from being stored in this Map.
  271.      * @exception IllegalArgumentException some aspect of a key or value in the
  272.      *              specified Map prevents it from being stored in this Map.
  273.      * @exception NullPointerException this Map does not permit null keys
  274.      *          or values, and the specified key or value is null.
  275.      */
  276.     public void putAll(Map t) {
  277.     Iterator i = t.entries().iterator();
  278.     while (i.hasNext()) {
  279.         Entry e = (Entry) i.next();
  280.         put(e.getKey(), e.getValue());
  281.     }
  282.     }
  283.  
  284.     /**
  285.      * Removes all mappings from this Map (optional operation).
  286.      * <p>
  287.      * This implementation calls <code>entries().clear()</code>.
  288.      *
  289.      * @exception UnsupportedOperationException clear is not supported
  290.      *           by this Map.
  291.      */
  292.     public void clear() {
  293.     entries().clear();
  294.     }
  295.  
  296.  
  297.     // Views
  298.  
  299.     private transient Set keySet = null;
  300.     /**
  301.      * Returns a Set view of the keys contained in this Map.  The Set is
  302.      * backed by the Map, so changes to the Map are reflected in the Set,
  303.      * and vice-versa.  (If the Map is modified while while an iteration over
  304.      * the Set is in progress, the results of the iteration are undefined.)
  305.      * The Set supports element removal, which removes the corresponding entry
  306.      * from the Map, via the Iterator.remove, Set.remove,  removeAll
  307.      * retainAll, and clear operations.  It does not support the add or
  308.      * addAll operations.
  309.      * <p>
  310.      * This implementation returns a Set that subclasses
  311.      * AbstractSet.  The subclass's iterator method returns a "wrapper
  312.      * object" over this Map's entries() Iterator.  The size method delegates
  313.      * to this Map's size method.
  314.      * <p>
  315.      * The Set is created the first time this method is called,
  316.      * and returned in response to all subsequent calls.  No synchronization
  317.      * is performed, so there is a slight chance that multiple calls to this
  318.      * method will not all return the same Set.
  319.      */
  320.     public Set keySet() {
  321.     if (keySet == null) {
  322.         keySet = new AbstractSet() {
  323.         public Iterator iterator() {
  324.             return new Iterator() {
  325.             private Iterator i = entries().iterator();
  326.  
  327.             public boolean hasNext() {
  328.                 return i.hasNext();
  329.             }
  330.  
  331.             public Object next() {
  332.                 return ((Entry)i.next()).getKey();
  333.             }
  334.  
  335.             public void remove() {
  336.                 i.remove();
  337.             }
  338.                     };
  339.         }
  340.  
  341.         public int size() {
  342.             return Map.this.size();
  343.         }
  344.         };
  345.     }
  346.     return keySet;
  347.     }
  348.  
  349.     private transient Collection values = null;
  350.     /**
  351.      * Returns a Collection view of the values contained in this Map.  The
  352.      * Collection is backed by the Map, so changes to the Map are
  353.      * reflected in the Collection, and vice-versa.  (If the Map is
  354.      * modified while while an iteration over the Collection is in progress,
  355.      * the results of the iteration are undefined.)  The Collection supports
  356.      * element removal, which removes the corresponding entry from the
  357.      * Map, via the Iterator.remove, Collection.remove, removeAll,
  358.      * retainAll and clear operations.  It does not support the add or
  359.      * addAll operations.
  360.      * <p>
  361.      * This implementation returns a Collection that subclasses
  362.      * AbstractCollection.  The subclass's iterator method returns a "wrapper
  363.      * object" over this Map's entries() Iterator.  The size method delegates
  364.      * to this Map's size method.
  365.      * <p>
  366.      * The Collection is created the first time this method is called,
  367.      * and returned in response to all subsequent calls.  No synchronization
  368.      * is performed, so there is a slight chance that multiple calls to this
  369.      * method will not all return the same Collection.
  370.      */
  371.     public Collection values() {
  372.     if (values == null) {
  373.         values = new AbstractCollection() {
  374.         public Iterator iterator() {
  375.             return new Iterator() {
  376.             private Iterator i = entries().iterator();
  377.  
  378.             public boolean hasNext() {
  379.                 return i.hasNext();
  380.             }
  381.  
  382.             public Object next() {
  383.                 return ((Entry)i.next()).getValue();
  384.             }
  385.  
  386.             public void remove() {
  387.                 i.remove();
  388.             }
  389.                     };
  390.                 }
  391.  
  392.         public int size() {
  393.             return Map.this.size();
  394.         }
  395.         };
  396.     }
  397.     return values;
  398.     }
  399.  
  400.     /**
  401.      * Returns a Set view of the mappings contained in this Map.  Each element
  402.      * in this Set is a Map.Entry.  The Set is backed by the Map, so changes
  403.      * to the Map are reflected in the Set, and vice-versa.  (If the Map is
  404.      * modified while while an iteration over the Set is in progress, the
  405.      * results of the iteration are undefined.)  The Set supports element
  406.      * removal, which removes the corresponding entry from the Map, via the
  407.      * Iterator.remove, Set.remove, removeAll, retainAll and clear operations.
  408.      * It does not support the add or addAll operations.
  409.      */
  410.     public abstract Set entries();
  411.  
  412.  
  413.     // Comparison and hashing
  414.  
  415.     /**
  416.      * Compares the specified Object with this Map for equality.
  417.      * Returns true if the given object is also a Map and the two
  418.      * Maps represent the same mappings.  More formally, two
  419.      * Maps <code>t1</code> and <code>t2</code> represent the same mappings
  420.      * if <code>t1.keySet().equals(t2.keySet())</code> and for every 
  421.      * key <code>k</code> in <code>t1.keySet()</code>, <code>
  422.      * (t1.get(k)==null ? t2.get(k)==null : t1.get(k).equals(t2.get(k)))
  423.      * </code>.  This ensures that the equals method works properly across
  424.      * different implementations of the Map interface.
  425.      * <p>
  426.      * This implementation first checks if the specified Object is this Map;
  427.      * if so it returns true.  Then, it checks if the specified Object is
  428.      * a Map whose size is identical to the size of this Set; if not, it
  429.      * it returns false.  If so, it iterates over this Map's entries()
  430.      * Collection, and checks that the specified Map contains each
  431.      * mapping that this Map contains.  If the specified Map fails
  432.      * to contain such a mapping, false is returned.  If the iteration
  433.      * completes, true is returned.
  434.      *
  435.      * @param o Object to be compared for equality with this Map.
  436.      * @return true if the specified Object is equal to this Map.
  437.      */
  438.     public boolean equals(Object o) {
  439.     if (o == this)
  440.         return true;
  441.  
  442.     if (!(o instanceof Map))
  443.         return false;
  444.     Map t = (Map) o;
  445.     if (t.size() != size())
  446.         return false;
  447.  
  448.     Iterator i = entries().iterator();
  449.     while (i.hasNext()) {
  450.         Entry e = (Entry) i.next();
  451.         Object key = e.getKey();
  452.         Object value = e.getValue();
  453.         if (value == null) {
  454.         if (!(t.get(key)==null && t.containsKey(key)))
  455.             return false;
  456.         } else {
  457.         if (!value.equals(t.get(key)))
  458.             return false;
  459.         }
  460.     }
  461.     return true;
  462.     }
  463.  
  464.     /**
  465.      * Returns the hash code value for this Map.  The hash code of a Map
  466.      * is defined to be the sum of the hashCodes of each Entry in the Map's
  467.      * entries() view.  This ensures that <code>t1.equals(t2)</code> implies
  468.      * that <code>t1.hashCode()==t2.hashCode()</code> for any two Maps
  469.      * <code>t1</code> and <code>t2</code>, as required by the general
  470.      * contract of Object.hashCode.
  471.      * <p>
  472.      * This implementation iterates over entries(), calling hashCode
  473.      * on each element (Entry) in the Collection, and adding up the results.
  474.      *
  475.      * @see Entry#hashCode()
  476.      * @see Object#hashCode()
  477.      * @see Object#equals(Object)
  478.      * @see Set#equals(Object)
  479.      */
  480.     public int hashCode() {
  481.     int h = 0;
  482.     Iterator i = entries().iterator();
  483.     while (i.hasNext())
  484.         h += i.next().hashCode();
  485.     return h;
  486.     }
  487.  
  488.     /**
  489.      * Returns a String representation of this Map.
  490.      */
  491.     public String toString() {
  492.     int max = size() - 1;
  493.     StringBuffer buf = new StringBuffer();
  494.     Iterator i = entries().iterator();
  495.  
  496.     buf.append("{");
  497.     for (int j = 0; j <= max; j++) {
  498.         Entry e = (Entry) (i.next());
  499.         buf.append(e.getKey() + "=" + e.getValue());
  500.         if (j < max)
  501.         buf.append(", ");
  502.     }
  503.     buf.append("}");
  504.     return buf.toString();
  505.     }
  506. }
  507.