Save This Page
Home » openjdk-7 » java » util » [javadoc | source]
    1   /*
    2    * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   
   26   package java.util;
   27   import java.util.Map.Entry;
   28   
   29   /**
   30    * This class provides a skeletal implementation of the <tt>Map</tt>
   31    * interface, to minimize the effort required to implement this interface.
   32    *
   33    * <p>To implement an unmodifiable map, the programmer needs only to extend this
   34    * class and provide an implementation for the <tt>entrySet</tt> method, which
   35    * returns a set-view of the map's mappings.  Typically, the returned set
   36    * will, in turn, be implemented atop <tt>AbstractSet</tt>.  This set should
   37    * not support the <tt>add</tt> or <tt>remove</tt> methods, and its iterator
   38    * should not support the <tt>remove</tt> method.
   39    *
   40    * <p>To implement a modifiable map, the programmer must additionally override
   41    * this class's <tt>put</tt> method (which otherwise throws an
   42    * <tt>UnsupportedOperationException</tt>), and the iterator returned by
   43    * <tt>entrySet().iterator()</tt> must additionally implement its
   44    * <tt>remove</tt> method.
   45    *
   46    * <p>The programmer should generally provide a void (no argument) and map
   47    * constructor, as per the recommendation in the <tt>Map</tt> interface
   48    * specification.
   49    *
   50    * <p>The documentation for each non-abstract method in this class describes its
   51    * implementation in detail.  Each of these methods may be overridden if the
   52    * map being implemented admits a more efficient implementation.
   53    *
   54    * <p>This class is a member of the
   55    * <a href="{@docRoot}/../technotes/guides/collections/index.html">
   56    * Java Collections Framework</a>.
   57    *
   58    * @param <K> the type of keys maintained by this map
   59    * @param <V> the type of mapped values
   60    *
   61    * @author  Josh Bloch
   62    * @author  Neal Gafter
   63    * @see Map
   64    * @see Collection
   65    * @since 1.2
   66    */
   67   
   68   public abstract class AbstractMap<K,V> implements Map<K,V> {
   69       /**
   70        * Sole constructor.  (For invocation by subclass constructors, typically
   71        * implicit.)
   72        */
   73       protected AbstractMap() {
   74       }
   75   
   76       // Query Operations
   77   
   78       /**
   79        * {@inheritDoc}
   80        *
   81        * <p>This implementation returns <tt>entrySet().size()</tt>.
   82        */
   83       public int size() {
   84           return entrySet().size();
   85       }
   86   
   87       /**
   88        * {@inheritDoc}
   89        *
   90        * <p>This implementation returns <tt>size() == 0</tt>.
   91        */
   92       public boolean isEmpty() {
   93           return size() == 0;
   94       }
   95   
   96       /**
   97        * {@inheritDoc}
   98        *
   99        * <p>This implementation iterates over <tt>entrySet()</tt> searching
  100        * for an entry with the specified value.  If such an entry is found,
  101        * <tt>true</tt> is returned.  If the iteration terminates without
  102        * finding such an entry, <tt>false</tt> is returned.  Note that this
  103        * implementation requires linear time in the size of the map.
  104        *
  105        * @throws ClassCastException   {@inheritDoc}
  106        * @throws NullPointerException {@inheritDoc}
  107        */
  108       public boolean containsValue(Object value) {
  109           Iterator<Entry<K,V>> i = entrySet().iterator();
  110           if (value==null) {
  111               while (i.hasNext()) {
  112                   Entry<K,V> e = i.next();
  113                   if (e.getValue()==null)
  114                       return true;
  115               }
  116           } else {
  117               while (i.hasNext()) {
  118                   Entry<K,V> e = i.next();
  119                   if (value.equals(e.getValue()))
  120                       return true;
  121               }
  122           }
  123           return false;
  124       }
  125   
  126       /**
  127        * {@inheritDoc}
  128        *
  129        * <p>This implementation iterates over <tt>entrySet()</tt> searching
  130        * for an entry with the specified key.  If such an entry is found,
  131        * <tt>true</tt> is returned.  If the iteration terminates without
  132        * finding such an entry, <tt>false</tt> is returned.  Note that this
  133        * implementation requires linear time in the size of the map; many
  134        * implementations will override this method.
  135        *
  136        * @throws ClassCastException   {@inheritDoc}
  137        * @throws NullPointerException {@inheritDoc}
  138        */
  139       public boolean containsKey(Object key) {
  140           Iterator<Map.Entry<K,V>> i = entrySet().iterator();
  141           if (key==null) {
  142               while (i.hasNext()) {
  143                   Entry<K,V> e = i.next();
  144                   if (e.getKey()==null)
  145                       return true;
  146               }
  147           } else {
  148               while (i.hasNext()) {
  149                   Entry<K,V> e = i.next();
  150                   if (key.equals(e.getKey()))
  151                       return true;
  152               }
  153           }
  154           return false;
  155       }
  156   
  157       /**
  158        * {@inheritDoc}
  159        *
  160        * <p>This implementation iterates over <tt>entrySet()</tt> searching
  161        * for an entry with the specified key.  If such an entry is found,
  162        * the entry's value is returned.  If the iteration terminates without
  163        * finding such an entry, <tt>null</tt> is returned.  Note that this
  164        * implementation requires linear time in the size of the map; many
  165        * implementations will override this method.
  166        *
  167        * @throws ClassCastException            {@inheritDoc}
  168        * @throws NullPointerException          {@inheritDoc}
  169        */
  170       public V get(Object key) {
  171           Iterator<Entry<K,V>> i = entrySet().iterator();
  172           if (key==null) {
  173               while (i.hasNext()) {
  174                   Entry<K,V> e = i.next();
  175                   if (e.getKey()==null)
  176                       return e.getValue();
  177               }
  178           } else {
  179               while (i.hasNext()) {
  180                   Entry<K,V> e = i.next();
  181                   if (key.equals(e.getKey()))
  182                       return e.getValue();
  183               }
  184           }
  185           return null;
  186       }
  187   
  188   
  189       // Modification Operations
  190   
  191       /**
  192        * {@inheritDoc}
  193        *
  194        * <p>This implementation always throws an
  195        * <tt>UnsupportedOperationException</tt>.
  196        *
  197        * @throws UnsupportedOperationException {@inheritDoc}
  198        * @throws ClassCastException            {@inheritDoc}
  199        * @throws NullPointerException          {@inheritDoc}
  200        * @throws IllegalArgumentException      {@inheritDoc}
  201        */
  202       public V put(K key, V value) {
  203           throw new UnsupportedOperationException();
  204       }
  205   
  206       /**
  207        * {@inheritDoc}
  208        *
  209        * <p>This implementation iterates over <tt>entrySet()</tt> searching for an
  210        * entry with the specified key.  If such an entry is found, its value is
  211        * obtained with its <tt>getValue</tt> operation, the entry is removed
  212        * from the collection (and the backing map) with the iterator's
  213        * <tt>remove</tt> operation, and the saved value is returned.  If the
  214        * iteration terminates without finding such an entry, <tt>null</tt> is
  215        * returned.  Note that this implementation requires linear time in the
  216        * size of the map; many implementations will override this method.
  217        *
  218        * <p>Note that this implementation throws an
  219        * <tt>UnsupportedOperationException</tt> if the <tt>entrySet</tt>
  220        * iterator does not support the <tt>remove</tt> method and this map
  221        * contains a mapping for the specified key.
  222        *
  223        * @throws UnsupportedOperationException {@inheritDoc}
  224        * @throws ClassCastException            {@inheritDoc}
  225        * @throws NullPointerException          {@inheritDoc}
  226        */
  227       public V remove(Object key) {
  228           Iterator<Entry<K,V>> i = entrySet().iterator();
  229           Entry<K,V> correctEntry = null;
  230           if (key==null) {
  231               while (correctEntry==null && i.hasNext()) {
  232                   Entry<K,V> e = i.next();
  233                   if (e.getKey()==null)
  234                       correctEntry = e;
  235               }
  236           } else {
  237               while (correctEntry==null && i.hasNext()) {
  238                   Entry<K,V> e = i.next();
  239                   if (key.equals(e.getKey()))
  240                       correctEntry = e;
  241               }
  242           }
  243   
  244           V oldValue = null;
  245           if (correctEntry !=null) {
  246               oldValue = correctEntry.getValue();
  247               i.remove();
  248           }
  249           return oldValue;
  250       }
  251   
  252   
  253       // Bulk Operations
  254   
  255       /**
  256        * {@inheritDoc}
  257        *
  258        * <p>This implementation iterates over the specified map's
  259        * <tt>entrySet()</tt> collection, and calls this map's <tt>put</tt>
  260        * operation once for each entry returned by the iteration.
  261        *
  262        * <p>Note that this implementation throws an
  263        * <tt>UnsupportedOperationException</tt> if this map does not support
  264        * the <tt>put</tt> operation and the specified map is nonempty.
  265        *
  266        * @throws UnsupportedOperationException {@inheritDoc}
  267        * @throws ClassCastException            {@inheritDoc}
  268        * @throws NullPointerException          {@inheritDoc}
  269        * @throws IllegalArgumentException      {@inheritDoc}
  270        */
  271       public void putAll(Map<? extends K, ? extends V> m) {
  272           for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
  273               put(e.getKey(), e.getValue());
  274       }
  275   
  276       /**
  277        * {@inheritDoc}
  278        *
  279        * <p>This implementation calls <tt>entrySet().clear()</tt>.
  280        *
  281        * <p>Note that this implementation throws an
  282        * <tt>UnsupportedOperationException</tt> if the <tt>entrySet</tt>
  283        * does not support the <tt>clear</tt> operation.
  284        *
  285        * @throws UnsupportedOperationException {@inheritDoc}
  286        */
  287       public void clear() {
  288           entrySet().clear();
  289       }
  290   
  291   
  292       // Views
  293   
  294       /**
  295        * Each of these fields are initialized to contain an instance of the
  296        * appropriate view the first time this view is requested.  The views are
  297        * stateless, so there's no reason to create more than one of each.
  298        */
  299       transient volatile Set<K>        keySet = null;
  300       transient volatile Collection<V> values = null;
  301   
  302       /**
  303        * {@inheritDoc}
  304        *
  305        * <p>This implementation returns a set that subclasses {@link AbstractSet}.
  306        * The subclass's iterator method returns a "wrapper object" over this
  307        * map's <tt>entrySet()</tt> iterator.  The <tt>size</tt> method
  308        * delegates to this map's <tt>size</tt> method and the
  309        * <tt>contains</tt> method delegates to this map's
  310        * <tt>containsKey</tt> method.
  311        *
  312        * <p>The set is created the first time this method is called,
  313        * and returned in response to all subsequent calls.  No synchronization
  314        * is performed, so there is a slight chance that multiple calls to this
  315        * method will not all return the same set.
  316        */
  317       public Set<K> keySet() {
  318           if (keySet == null) {
  319               keySet = new AbstractSet<K>() {
  320                   public Iterator<K> iterator() {
  321                       return new Iterator<K>() {
  322                           private Iterator<Entry<K,V>> i = entrySet().iterator();
  323   
  324                           public boolean hasNext() {
  325                               return i.hasNext();
  326                           }
  327   
  328                           public K next() {
  329                               return i.next().getKey();
  330                           }
  331   
  332                           public void remove() {
  333                               i.remove();
  334                           }
  335                       };
  336                   }
  337   
  338                   public int size() {
  339                       return AbstractMap.this.size();
  340                   }
  341   
  342                   public boolean isEmpty() {
  343                       return AbstractMap.this.isEmpty();
  344                   }
  345   
  346                   public void clear() {
  347                       AbstractMap.this.clear();
  348                   }
  349   
  350                   public boolean contains(Object k) {
  351                       return AbstractMap.this.containsKey(k);
  352                   }
  353               };
  354           }
  355           return keySet;
  356       }
  357   
  358       /**
  359        * {@inheritDoc}
  360        *
  361        * <p>This implementation returns a collection that subclasses {@link
  362        * AbstractCollection}.  The subclass's iterator method returns a
  363        * "wrapper object" over this map's <tt>entrySet()</tt> iterator.
  364        * The <tt>size</tt> method delegates to this map's <tt>size</tt>
  365        * method and the <tt>contains</tt> method delegates to this map's
  366        * <tt>containsValue</tt> method.
  367        *
  368        * <p>The collection is created the first time this method is called, and
  369        * returned in response to all subsequent calls.  No synchronization is
  370        * performed, so there is a slight chance that multiple calls to this
  371        * method will not all return the same collection.
  372        */
  373       public Collection<V> values() {
  374           if (values == null) {
  375               values = new AbstractCollection<V>() {
  376                   public Iterator<V> iterator() {
  377                       return new Iterator<V>() {
  378                           private Iterator<Entry<K,V>> i = entrySet().iterator();
  379   
  380                           public boolean hasNext() {
  381                               return i.hasNext();
  382                           }
  383   
  384                           public V next() {
  385                               return i.next().getValue();
  386                           }
  387   
  388                           public void remove() {
  389                               i.remove();
  390                           }
  391                       };
  392                   }
  393   
  394                   public int size() {
  395                       return AbstractMap.this.size();
  396                   }
  397   
  398                   public boolean isEmpty() {
  399                       return AbstractMap.this.isEmpty();
  400                   }
  401   
  402                   public void clear() {
  403                       AbstractMap.this.clear();
  404                   }
  405   
  406                   public boolean contains(Object v) {
  407                       return AbstractMap.this.containsValue(v);
  408                   }
  409               };
  410           }
  411           return values;
  412       }
  413   
  414       public abstract Set<Entry<K,V>> entrySet();
  415   
  416   
  417       // Comparison and hashing
  418   
  419       /**
  420        * Compares the specified object with this map for equality.  Returns
  421        * <tt>true</tt> if the given object is also a map and the two maps
  422        * represent the same mappings.  More formally, two maps <tt>m1</tt> and
  423        * <tt>m2</tt> represent the same mappings if
  424        * <tt>m1.entrySet().equals(m2.entrySet())</tt>.  This ensures that the
  425        * <tt>equals</tt> method works properly across different implementations
  426        * of the <tt>Map</tt> interface.
  427        *
  428        * <p>This implementation first checks if the specified object is this map;
  429        * if so it returns <tt>true</tt>.  Then, it checks if the specified
  430        * object is a map whose size is identical to the size of this map; if
  431        * not, it returns <tt>false</tt>.  If so, it iterates over this map's
  432        * <tt>entrySet</tt> collection, and checks that the specified map
  433        * contains each mapping that this map contains.  If the specified map
  434        * fails to contain such a mapping, <tt>false</tt> is returned.  If the
  435        * iteration completes, <tt>true</tt> is returned.
  436        *
  437        * @param o object to be compared for equality with this map
  438        * @return <tt>true</tt> if the specified object is equal to this map
  439        */
  440       public boolean equals(Object o) {
  441           if (o == this)
  442               return true;
  443   
  444           if (!(o instanceof Map))
  445               return false;
  446           Map<K,V> m = (Map<K,V>) o;
  447           if (m.size() != size())
  448               return false;
  449   
  450           try {
  451               Iterator<Entry<K,V>> i = entrySet().iterator();
  452               while (i.hasNext()) {
  453                   Entry<K,V> e = i.next();
  454                   K key = e.getKey();
  455                   V value = e.getValue();
  456                   if (value == null) {
  457                       if (!(m.get(key)==null && m.containsKey(key)))
  458                           return false;
  459                   } else {
  460                       if (!value.equals(m.get(key)))
  461                           return false;
  462                   }
  463               }
  464           } catch (ClassCastException unused) {
  465               return false;
  466           } catch (NullPointerException unused) {
  467               return false;
  468           }
  469   
  470           return true;
  471       }
  472   
  473       /**
  474        * Returns the hash code value for this map.  The hash code of a map is
  475        * defined to be the sum of the hash codes of each entry in the map's
  476        * <tt>entrySet()</tt> view.  This ensures that <tt>m1.equals(m2)</tt>
  477        * implies that <tt>m1.hashCode()==m2.hashCode()</tt> for any two maps
  478        * <tt>m1</tt> and <tt>m2</tt>, as required by the general contract of
  479        * {@link Object#hashCode}.
  480        *
  481        * <p>This implementation iterates over <tt>entrySet()</tt>, calling
  482        * {@link Map.Entry#hashCode hashCode()} on each element (entry) in the
  483        * set, and adding up the results.
  484        *
  485        * @return the hash code value for this map
  486        * @see Map.Entry#hashCode()
  487        * @see Object#equals(Object)
  488        * @see Set#equals(Object)
  489        */
  490       public int hashCode() {
  491           int h = 0;
  492           Iterator<Entry<K,V>> i = entrySet().iterator();
  493           while (i.hasNext())
  494               h += i.next().hashCode();
  495           return h;
  496       }
  497   
  498       /**
  499        * Returns a string representation of this map.  The string representation
  500        * consists of a list of key-value mappings in the order returned by the
  501        * map's <tt>entrySet</tt> view's iterator, enclosed in braces
  502        * (<tt>"{}"</tt>).  Adjacent mappings are separated by the characters
  503        * <tt>", "</tt> (comma and space).  Each key-value mapping is rendered as
  504        * the key followed by an equals sign (<tt>"="</tt>) followed by the
  505        * associated value.  Keys and values are converted to strings as by
  506        * {@link String#valueOf(Object)}.
  507        *
  508        * @return a string representation of this map
  509        */
  510       public String toString() {
  511           Iterator<Entry<K,V>> i = entrySet().iterator();
  512           if (! i.hasNext())
  513               return "{}";
  514   
  515           StringBuilder sb = new StringBuilder();
  516           sb.append('{');
  517           for (;;) {
  518               Entry<K,V> e = i.next();
  519               K key = e.getKey();
  520               V value = e.getValue();
  521               sb.append(key   == this ? "(this Map)" : key);
  522               sb.append('=');
  523               sb.append(value == this ? "(this Map)" : value);
  524               if (! i.hasNext())
  525                   return sb.append('}').toString();
  526               sb.append(',').append(' ');
  527           }
  528       }
  529   
  530       /**
  531        * Returns a shallow copy of this <tt>AbstractMap</tt> instance: the keys
  532        * and values themselves are not cloned.
  533        *
  534        * @return a shallow copy of this map
  535        */
  536       protected Object clone() throws CloneNotSupportedException {
  537           AbstractMap<K,V> result = (AbstractMap<K,V>)super.clone();
  538           result.keySet = null;
  539           result.values = null;
  540           return result;
  541       }
  542   
  543       /**
  544        * Utility method for SimpleEntry and SimpleImmutableEntry.
  545        * Test for equality, checking for nulls.
  546        */
  547       private static boolean eq(Object o1, Object o2) {
  548           return o1 == null ? o2 == null : o1.equals(o2);
  549       }
  550   
  551       // Implementation Note: SimpleEntry and SimpleImmutableEntry
  552       // are distinct unrelated classes, even though they share
  553       // some code. Since you can't add or subtract final-ness
  554       // of a field in a subclass, they can't share representations,
  555       // and the amount of duplicated code is too small to warrant
  556       // exposing a common abstract class.
  557   
  558   
  559       /**
  560        * An Entry maintaining a key and a value.  The value may be
  561        * changed using the <tt>setValue</tt> method.  This class
  562        * facilitates the process of building custom map
  563        * implementations. For example, it may be convenient to return
  564        * arrays of <tt>SimpleEntry</tt> instances in method
  565        * <tt>Map.entrySet().toArray</tt>.
  566        *
  567        * @since 1.6
  568        */
  569       public static class SimpleEntry<K,V>
  570           implements Entry<K,V>, java.io.Serializable
  571       {
  572           private static final long serialVersionUID = -8499721149061103585L;
  573   
  574           private final K key;
  575           private V value;
  576   
  577           /**
  578            * Creates an entry representing a mapping from the specified
  579            * key to the specified value.
  580            *
  581            * @param key the key represented by this entry
  582            * @param value the value represented by this entry
  583            */
  584           public SimpleEntry(K key, V value) {
  585               this.key   = key;
  586               this.value = value;
  587           }
  588   
  589           /**
  590            * Creates an entry representing the same mapping as the
  591            * specified entry.
  592            *
  593            * @param entry the entry to copy
  594            */
  595           public SimpleEntry(Entry<? extends K, ? extends V> entry) {
  596               this.key   = entry.getKey();
  597               this.value = entry.getValue();
  598           }
  599   
  600           /**
  601            * Returns the key corresponding to this entry.
  602            *
  603            * @return the key corresponding to this entry
  604            */
  605           public K getKey() {
  606               return key;
  607           }
  608   
  609           /**
  610            * Returns the value corresponding to this entry.
  611            *
  612            * @return the value corresponding to this entry
  613            */
  614           public V getValue() {
  615               return value;
  616           }
  617   
  618           /**
  619            * Replaces the value corresponding to this entry with the specified
  620            * value.
  621            *
  622            * @param value new value to be stored in this entry
  623            * @return the old value corresponding to the entry
  624            */
  625           public V setValue(V value) {
  626               V oldValue = this.value;
  627               this.value = value;
  628               return oldValue;
  629           }
  630   
  631           /**
  632            * Compares the specified object with this entry for equality.
  633            * Returns {@code true} if the given object is also a map entry and
  634            * the two entries represent the same mapping.  More formally, two
  635            * entries {@code e1} and {@code e2} represent the same mapping
  636            * if<pre>
  637            *   (e1.getKey()==null ?
  638            *    e2.getKey()==null :
  639            *    e1.getKey().equals(e2.getKey()))
  640            *   &amp;&amp;
  641            *   (e1.getValue()==null ?
  642            *    e2.getValue()==null :
  643            *    e1.getValue().equals(e2.getValue()))</pre>
  644            * This ensures that the {@code equals} method works properly across
  645            * different implementations of the {@code Map.Entry} interface.
  646            *
  647            * @param o object to be compared for equality with this map entry
  648            * @return {@code true} if the specified object is equal to this map
  649            *         entry
  650            * @see    #hashCode
  651            */
  652           public boolean equals(Object o) {
  653               if (!(o instanceof Map.Entry))
  654                   return false;
  655               Map.Entry e = (Map.Entry)o;
  656               return eq(key, e.getKey()) && eq(value, e.getValue());
  657           }
  658   
  659           /**
  660            * Returns the hash code value for this map entry.  The hash code
  661            * of a map entry {@code e} is defined to be: <pre>
  662            *   (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
  663            *   (e.getValue()==null ? 0 : e.getValue().hashCode())</pre>
  664            * This ensures that {@code e1.equals(e2)} implies that
  665            * {@code e1.hashCode()==e2.hashCode()} for any two Entries
  666            * {@code e1} and {@code e2}, as required by the general
  667            * contract of {@link Object#hashCode}.
  668            *
  669            * @return the hash code value for this map entry
  670            * @see    #equals
  671            */
  672           public int hashCode() {
  673               return (key   == null ? 0 :   key.hashCode()) ^
  674                      (value == null ? 0 : value.hashCode());
  675           }
  676   
  677           /**
  678            * Returns a String representation of this map entry.  This
  679            * implementation returns the string representation of this
  680            * entry's key followed by the equals character ("<tt>=</tt>")
  681            * followed by the string representation of this entry's value.
  682            *
  683            * @return a String representation of this map entry
  684            */
  685           public String toString() {
  686               return key + "=" + value;
  687           }
  688   
  689       }
  690   
  691       /**
  692        * An Entry maintaining an immutable key and value.  This class
  693        * does not support method <tt>setValue</tt>.  This class may be
  694        * convenient in methods that return thread-safe snapshots of
  695        * key-value mappings.
  696        *
  697        * @since 1.6
  698        */
  699       public static class SimpleImmutableEntry<K,V>
  700           implements Entry<K,V>, java.io.Serializable
  701       {
  702           private static final long serialVersionUID = 7138329143949025153L;
  703   
  704           private final K key;
  705           private final V value;
  706   
  707           /**
  708            * Creates an entry representing a mapping from the specified
  709            * key to the specified value.
  710            *
  711            * @param key the key represented by this entry
  712            * @param value the value represented by this entry
  713            */
  714           public SimpleImmutableEntry(K key, V value) {
  715               this.key   = key;
  716               this.value = value;
  717           }
  718   
  719           /**
  720            * Creates an entry representing the same mapping as the
  721            * specified entry.
  722            *
  723            * @param entry the entry to copy
  724            */
  725           public SimpleImmutableEntry(Entry<? extends K, ? extends V> entry) {
  726               this.key   = entry.getKey();
  727               this.value = entry.getValue();
  728           }
  729   
  730           /**
  731            * Returns the key corresponding to this entry.
  732            *
  733            * @return the key corresponding to this entry
  734            */
  735           public K getKey() {
  736               return key;
  737           }
  738   
  739           /**
  740            * Returns the value corresponding to this entry.
  741            *
  742            * @return the value corresponding to this entry
  743            */
  744           public V getValue() {
  745               return value;
  746           }
  747   
  748           /**
  749            * Replaces the value corresponding to this entry with the specified
  750            * value (optional operation).  This implementation simply throws
  751            * <tt>UnsupportedOperationException</tt>, as this class implements
  752            * an <i>immutable</i> map entry.
  753            *
  754            * @param value new value to be stored in this entry
  755            * @return (Does not return)
  756            * @throws UnsupportedOperationException always
  757            */
  758           public V setValue(V value) {
  759               throw new UnsupportedOperationException();
  760           }
  761   
  762           /**
  763            * Compares the specified object with this entry for equality.
  764            * Returns {@code true} if the given object is also a map entry and
  765            * the two entries represent the same mapping.  More formally, two
  766            * entries {@code e1} and {@code e2} represent the same mapping
  767            * if<pre>
  768            *   (e1.getKey()==null ?
  769            *    e2.getKey()==null :
  770            *    e1.getKey().equals(e2.getKey()))
  771            *   &amp;&amp;
  772            *   (e1.getValue()==null ?
  773            *    e2.getValue()==null :
  774            *    e1.getValue().equals(e2.getValue()))</pre>
  775            * This ensures that the {@code equals} method works properly across
  776            * different implementations of the {@code Map.Entry} interface.
  777            *
  778            * @param o object to be compared for equality with this map entry
  779            * @return {@code true} if the specified object is equal to this map
  780            *         entry
  781            * @see    #hashCode
  782            */
  783           public boolean equals(Object o) {
  784               if (!(o instanceof Map.Entry))
  785                   return false;
  786               Map.Entry e = (Map.Entry)o;
  787               return eq(key, e.getKey()) && eq(value, e.getValue());
  788           }
  789   
  790           /**
  791            * Returns the hash code value for this map entry.  The hash code
  792            * of a map entry {@code e} is defined to be: <pre>
  793            *   (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
  794            *   (e.getValue()==null ? 0 : e.getValue().hashCode())</pre>
  795            * This ensures that {@code e1.equals(e2)} implies that
  796            * {@code e1.hashCode()==e2.hashCode()} for any two Entries
  797            * {@code e1} and {@code e2}, as required by the general
  798            * contract of {@link Object#hashCode}.
  799            *
  800            * @return the hash code value for this map entry
  801            * @see    #equals
  802            */
  803           public int hashCode() {
  804               return (key   == null ? 0 :   key.hashCode()) ^
  805                      (value == null ? 0 : value.hashCode());
  806           }
  807   
  808           /**
  809            * Returns a String representation of this map entry.  This
  810            * implementation returns the string representation of this
  811            * entry's key followed by the equals character ("<tt>=</tt>")
  812            * followed by the string representation of this entry's value.
  813            *
  814            * @return a String representation of this map entry
  815            */
  816           public String toString() {
  817               return key + "=" + value;
  818           }
  819   
  820       }
  821   
  822   }

Save This Page
Home » openjdk-7 » java » util » [javadoc | source]