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

    1   /*
    2    * Copyright (c) 2003, 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   
   28   import java.util.Map.Entry;
   29   import sun.misc.SharedSecrets;
   30   
   31   /**
   32    * A specialized {@link Map} implementation for use with enum type keys.  All
   33    * of the keys in an enum map must come from a single enum type that is
   34    * specified, explicitly or implicitly, when the map is created.  Enum maps
   35    * are represented internally as arrays.  This representation is extremely
   36    * compact and efficient.
   37    *
   38    * <p>Enum maps are maintained in the <i>natural order</i> of their keys
   39    * (the order in which the enum constants are declared).  This is reflected
   40    * in the iterators returned by the collections views ({@link #keySet()},
   41    * {@link #entrySet()}, and {@link #values()}).
   42    *
   43    * <p>Iterators returned by the collection views are <i>weakly consistent</i>:
   44    * they will never throw {@link ConcurrentModificationException} and they may
   45    * or may not show the effects of any modifications to the map that occur while
   46    * the iteration is in progress.
   47    *
   48    * <p>Null keys are not permitted.  Attempts to insert a null key will
   49    * throw {@link NullPointerException}.  Attempts to test for the
   50    * presence of a null key or to remove one will, however, function properly.
   51    * Null values are permitted.
   52   
   53    * <P>Like most collection implementations <tt>EnumMap</tt> is not
   54    * synchronized. If multiple threads access an enum map concurrently, and at
   55    * least one of the threads modifies the map, it should be synchronized
   56    * externally.  This is typically accomplished by synchronizing on some
   57    * object that naturally encapsulates the enum map.  If no such object exists,
   58    * the map should be "wrapped" using the {@link Collections#synchronizedMap}
   59    * method.  This is best done at creation time, to prevent accidental
   60    * unsynchronized access:
   61    *
   62    * <pre>
   63    *     Map&lt;EnumKey, V&gt; m
   64    *         = Collections.synchronizedMap(new EnumMap&lt;EnumKey, V&gt;(...));
   65    * </pre>
   66    *
   67    * <p>Implementation note: All basic operations execute in constant time.
   68    * They are likely (though not guaranteed) to be faster than their
   69    * {@link HashMap} counterparts.
   70    *
   71    * <p>This class is a member of the
   72    * <a href="{@docRoot}/../technotes/guides/collections/index.html">
   73    * Java Collections Framework</a>.
   74    *
   75    * @author Josh Bloch
   76    * @see EnumSet
   77    * @since 1.5
   78    */
   79   public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V>
   80       implements java.io.Serializable, Cloneable
   81   {
   82       /**
   83        * The <tt>Class</tt> object for the enum type of all the keys of this map.
   84        *
   85        * @serial
   86        */
   87       private final Class<K> keyType;
   88   
   89       /**
   90        * All of the values comprising K.  (Cached for performance.)
   91        */
   92       private transient K[] keyUniverse;
   93   
   94       /**
   95        * Array representation of this map.  The ith element is the value
   96        * to which universe[i] is currently mapped, or null if it isn't
   97        * mapped to anything, or NULL if it's mapped to null.
   98        */
   99       private transient Object[] vals;
  100   
  101       /**
  102        * The number of mappings in this map.
  103        */
  104       private transient int size = 0;
  105   
  106       /**
  107        * Distinguished non-null value for representing null values.
  108        */
  109       private static final Object NULL = new Integer(0);
  110   
  111       private Object maskNull(Object value) {
  112           return (value == null ? NULL : value);
  113       }
  114   
  115       private V unmaskNull(Object value) {
  116           return (V) (value == NULL ? null : value);
  117       }
  118   
  119       private static final Enum[] ZERO_LENGTH_ENUM_ARRAY = new Enum[0];
  120   
  121       /**
  122        * Creates an empty enum map with the specified key type.
  123        *
  124        * @param keyType the class object of the key type for this enum map
  125        * @throws NullPointerException if <tt>keyType</tt> is null
  126        */
  127       public EnumMap(Class<K> keyType) {
  128           this.keyType = keyType;
  129           keyUniverse = getKeyUniverse(keyType);
  130           vals = new Object[keyUniverse.length];
  131       }
  132   
  133       /**
  134        * Creates an enum map with the same key type as the specified enum
  135        * map, initially containing the same mappings (if any).
  136        *
  137        * @param m the enum map from which to initialize this enum map
  138        * @throws NullPointerException if <tt>m</tt> is null
  139        */
  140       public EnumMap(EnumMap<K, ? extends V> m) {
  141           keyType = m.keyType;
  142           keyUniverse = m.keyUniverse;
  143           vals = m.vals.clone();
  144           size = m.size;
  145       }
  146   
  147       /**
  148        * Creates an enum map initialized from the specified map.  If the
  149        * specified map is an <tt>EnumMap</tt> instance, this constructor behaves
  150        * identically to {@link #EnumMap(EnumMap)}.  Otherwise, the specified map
  151        * must contain at least one mapping (in order to determine the new
  152        * enum map's key type).
  153        *
  154        * @param m the map from which to initialize this enum map
  155        * @throws IllegalArgumentException if <tt>m</tt> is not an
  156        *     <tt>EnumMap</tt> instance and contains no mappings
  157        * @throws NullPointerException if <tt>m</tt> is null
  158        */
  159       public EnumMap(Map<K, ? extends V> m) {
  160           if (m instanceof EnumMap) {
  161               EnumMap<K, ? extends V> em = (EnumMap<K, ? extends V>) m;
  162               keyType = em.keyType;
  163               keyUniverse = em.keyUniverse;
  164               vals = em.vals.clone();
  165               size = em.size;
  166           } else {
  167               if (m.isEmpty())
  168                   throw new IllegalArgumentException("Specified map is empty");
  169               keyType = m.keySet().iterator().next().getDeclaringClass();
  170               keyUniverse = getKeyUniverse(keyType);
  171               vals = new Object[keyUniverse.length];
  172               putAll(m);
  173           }
  174       }
  175   
  176       // Query Operations
  177   
  178       /**
  179        * Returns the number of key-value mappings in this map.
  180        *
  181        * @return the number of key-value mappings in this map
  182        */
  183       public int size() {
  184           return size;
  185       }
  186   
  187       /**
  188        * Returns <tt>true</tt> if this map maps one or more keys to the
  189        * specified value.
  190        *
  191        * @param value the value whose presence in this map is to be tested
  192        * @return <tt>true</tt> if this map maps one or more keys to this value
  193        */
  194       public boolean containsValue(Object value) {
  195           value = maskNull(value);
  196   
  197           for (Object val : vals)
  198               if (value.equals(val))
  199                   return true;
  200   
  201           return false;
  202       }
  203   
  204       /**
  205        * Returns <tt>true</tt> if this map contains a mapping for the specified
  206        * key.
  207        *
  208        * @param key the key whose presence in this map is to be tested
  209        * @return <tt>true</tt> if this map contains a mapping for the specified
  210        *            key
  211        */
  212       public boolean containsKey(Object key) {
  213           return isValidKey(key) && vals[((Enum)key).ordinal()] != null;
  214       }
  215   
  216       private boolean containsMapping(Object key, Object value) {
  217           return isValidKey(key) &&
  218               maskNull(value).equals(vals[((Enum)key).ordinal()]);
  219       }
  220   
  221       /**
  222        * Returns the value to which the specified key is mapped,
  223        * or {@code null} if this map contains no mapping for the key.
  224        *
  225        * <p>More formally, if this map contains a mapping from a key
  226        * {@code k} to a value {@code v} such that {@code (key == k)},
  227        * then this method returns {@code v}; otherwise it returns
  228        * {@code null}.  (There can be at most one such mapping.)
  229        *
  230        * <p>A return value of {@code null} does not <i>necessarily</i>
  231        * indicate that the map contains no mapping for the key; it's also
  232        * possible that the map explicitly maps the key to {@code null}.
  233        * The {@link #containsKey containsKey} operation may be used to
  234        * distinguish these two cases.
  235        */
  236       public V get(Object key) {
  237           return (isValidKey(key) ?
  238                   unmaskNull(vals[((Enum)key).ordinal()]) : null);
  239       }
  240   
  241       // Modification Operations
  242   
  243       /**
  244        * Associates the specified value with the specified key in this map.
  245        * If the map previously contained a mapping for this key, the old
  246        * value is replaced.
  247        *
  248        * @param key the key with which the specified value is to be associated
  249        * @param value the value to be associated with the specified key
  250        *
  251        * @return the previous value associated with specified key, or
  252        *     <tt>null</tt> if there was no mapping for key.  (A <tt>null</tt>
  253        *     return can also indicate that the map previously associated
  254        *     <tt>null</tt> with the specified key.)
  255        * @throws NullPointerException if the specified key is null
  256        */
  257       public V put(K key, V value) {
  258           typeCheck(key);
  259   
  260           int index = key.ordinal();
  261           Object oldValue = vals[index];
  262           vals[index] = maskNull(value);
  263           if (oldValue == null)
  264               size++;
  265           return unmaskNull(oldValue);
  266       }
  267   
  268       /**
  269        * Removes the mapping for this key from this map if present.
  270        *
  271        * @param key the key whose mapping is to be removed from the map
  272        * @return the previous value associated with specified key, or
  273        *     <tt>null</tt> if there was no entry for key.  (A <tt>null</tt>
  274        *     return can also indicate that the map previously associated
  275        *     <tt>null</tt> with the specified key.)
  276        */
  277       public V remove(Object key) {
  278           if (!isValidKey(key))
  279               return null;
  280           int index = ((Enum)key).ordinal();
  281           Object oldValue = vals[index];
  282           vals[index] = null;
  283           if (oldValue != null)
  284               size--;
  285           return unmaskNull(oldValue);
  286       }
  287   
  288       private boolean removeMapping(Object key, Object value) {
  289           if (!isValidKey(key))
  290               return false;
  291           int index = ((Enum)key).ordinal();
  292           if (maskNull(value).equals(vals[index])) {
  293               vals[index] = null;
  294               size--;
  295               return true;
  296           }
  297           return false;
  298       }
  299   
  300       /**
  301        * Returns true if key is of the proper type to be a key in this
  302        * enum map.
  303        */
  304       private boolean isValidKey(Object key) {
  305           if (key == null)
  306               return false;
  307   
  308           // Cheaper than instanceof Enum followed by getDeclaringClass
  309           Class keyClass = key.getClass();
  310           return keyClass == keyType || keyClass.getSuperclass() == keyType;
  311       }
  312   
  313       // Bulk Operations
  314   
  315       /**
  316        * Copies all of the mappings from the specified map to this map.
  317        * These mappings will replace any mappings that this map had for
  318        * any of the keys currently in the specified map.
  319        *
  320        * @param m the mappings to be stored in this map
  321        * @throws NullPointerException the specified map is null, or if
  322        *     one or more keys in the specified map are null
  323        */
  324       public void putAll(Map<? extends K, ? extends V> m) {
  325           if (m instanceof EnumMap) {
  326               EnumMap<? extends K, ? extends V> em =
  327                   (EnumMap<? extends K, ? extends V>)m;
  328               if (em.keyType != keyType) {
  329                   if (em.isEmpty())
  330                       return;
  331                   throw new ClassCastException(em.keyType + " != " + keyType);
  332               }
  333   
  334               for (int i = 0; i < keyUniverse.length; i++) {
  335                   Object emValue = em.vals[i];
  336                   if (emValue != null) {
  337                       if (vals[i] == null)
  338                           size++;
  339                       vals[i] = emValue;
  340                   }
  341               }
  342           } else {
  343               super.putAll(m);
  344           }
  345       }
  346   
  347       /**
  348        * Removes all mappings from this map.
  349        */
  350       public void clear() {
  351           Arrays.fill(vals, null);
  352           size = 0;
  353       }
  354   
  355       // Views
  356   
  357       /**
  358        * This field is initialized to contain an instance of the entry set
  359        * view the first time this view is requested.  The view is stateless,
  360        * so there's no reason to create more than one.
  361        */
  362       private transient Set<Map.Entry<K,V>> entrySet = null;
  363   
  364       /**
  365        * Returns a {@link Set} view of the keys contained in this map.
  366        * The returned set obeys the general contract outlined in
  367        * {@link Map#keySet()}.  The set's iterator will return the keys
  368        * in their natural order (the order in which the enum constants
  369        * are declared).
  370        *
  371        * @return a set view of the keys contained in this enum map
  372        */
  373       public Set<K> keySet() {
  374           Set<K> ks = keySet;
  375           if (ks != null)
  376               return ks;
  377           else
  378               return keySet = new KeySet();
  379       }
  380   
  381       private class KeySet extends AbstractSet<K> {
  382           public Iterator<K> iterator() {
  383               return new KeyIterator();
  384           }
  385           public int size() {
  386               return size;
  387           }
  388           public boolean contains(Object o) {
  389               return containsKey(o);
  390           }
  391           public boolean remove(Object o) {
  392               int oldSize = size;
  393               EnumMap.this.remove(o);
  394               return size != oldSize;
  395           }
  396           public void clear() {
  397               EnumMap.this.clear();
  398           }
  399       }
  400   
  401       /**
  402        * Returns a {@link Collection} view of the values contained in this map.
  403        * The returned collection obeys the general contract outlined in
  404        * {@link Map#values()}.  The collection's iterator will return the
  405        * values in the order their corresponding keys appear in map,
  406        * which is their natural order (the order in which the enum constants
  407        * are declared).
  408        *
  409        * @return a collection view of the values contained in this map
  410        */
  411       public Collection<V> values() {
  412           Collection<V> vs = values;
  413           if (vs != null)
  414               return vs;
  415           else
  416               return values = new Values();
  417       }
  418   
  419       private class Values extends AbstractCollection<V> {
  420           public Iterator<V> iterator() {
  421               return new ValueIterator();
  422           }
  423           public int size() {
  424               return size;
  425           }
  426           public boolean contains(Object o) {
  427               return containsValue(o);
  428           }
  429           public boolean remove(Object o) {
  430               o = maskNull(o);
  431   
  432               for (int i = 0; i < vals.length; i++) {
  433                   if (o.equals(vals[i])) {
  434                       vals[i] = null;
  435                       size--;
  436                       return true;
  437                   }
  438               }
  439               return false;
  440           }
  441           public void clear() {
  442               EnumMap.this.clear();
  443           }
  444       }
  445   
  446       /**
  447        * Returns a {@link Set} view of the mappings contained in this map.
  448        * The returned set obeys the general contract outlined in
  449        * {@link Map#keySet()}.  The set's iterator will return the
  450        * mappings in the order their keys appear in map, which is their
  451        * natural order (the order in which the enum constants are declared).
  452        *
  453        * @return a set view of the mappings contained in this enum map
  454        */
  455       public Set<Map.Entry<K,V>> entrySet() {
  456           Set<Map.Entry<K,V>> es = entrySet;
  457           if (es != null)
  458               return es;
  459           else
  460               return entrySet = new EntrySet();
  461       }
  462   
  463       private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
  464           public Iterator<Map.Entry<K,V>> iterator() {
  465               return new EntryIterator();
  466           }
  467   
  468           public boolean contains(Object o) {
  469               if (!(o instanceof Map.Entry))
  470                   return false;
  471               Map.Entry entry = (Map.Entry)o;
  472               return containsMapping(entry.getKey(), entry.getValue());
  473           }
  474           public boolean remove(Object o) {
  475               if (!(o instanceof Map.Entry))
  476                   return false;
  477               Map.Entry entry = (Map.Entry)o;
  478               return removeMapping(entry.getKey(), entry.getValue());
  479           }
  480           public int size() {
  481               return size;
  482           }
  483           public void clear() {
  484               EnumMap.this.clear();
  485           }
  486           public Object[] toArray() {
  487               return fillEntryArray(new Object[size]);
  488           }
  489           @SuppressWarnings("unchecked")
  490           public <T> T[] toArray(T[] a) {
  491               int size = size();
  492               if (a.length < size)
  493                   a = (T[])java.lang.reflect.Array
  494                       .newInstance(a.getClass().getComponentType(), size);
  495               if (a.length > size)
  496                   a[size] = null;
  497               return (T[]) fillEntryArray(a);
  498           }
  499           private Object[] fillEntryArray(Object[] a) {
  500               int j = 0;
  501               for (int i = 0; i < vals.length; i++)
  502                   if (vals[i] != null)
  503                       a[j++] = new AbstractMap.SimpleEntry<>(
  504                           keyUniverse[i], unmaskNull(vals[i]));
  505               return a;
  506           }
  507       }
  508   
  509       private abstract class EnumMapIterator<T> implements Iterator<T> {
  510           // Lower bound on index of next element to return
  511           int index = 0;
  512   
  513           // Index of last returned element, or -1 if none
  514           int lastReturnedIndex = -1;
  515   
  516           public boolean hasNext() {
  517               while (index < vals.length && vals[index] == null)
  518                   index++;
  519               return index != vals.length;
  520           }
  521   
  522           public void remove() {
  523               checkLastReturnedIndex();
  524   
  525               if (vals[lastReturnedIndex] != null) {
  526                   vals[lastReturnedIndex] = null;
  527                   size--;
  528               }
  529               lastReturnedIndex = -1;
  530           }
  531   
  532           private void checkLastReturnedIndex() {
  533               if (lastReturnedIndex < 0)
  534                   throw new IllegalStateException();
  535           }
  536       }
  537   
  538       private class KeyIterator extends EnumMapIterator<K> {
  539           public K next() {
  540               if (!hasNext())
  541                   throw new NoSuchElementException();
  542               lastReturnedIndex = index++;
  543               return keyUniverse[lastReturnedIndex];
  544           }
  545       }
  546   
  547       private class ValueIterator extends EnumMapIterator<V> {
  548           public V next() {
  549               if (!hasNext())
  550                   throw new NoSuchElementException();
  551               lastReturnedIndex = index++;
  552               return unmaskNull(vals[lastReturnedIndex]);
  553           }
  554       }
  555   
  556       private class EntryIterator extends EnumMapIterator<Map.Entry<K,V>> {
  557           private Entry lastReturnedEntry = null;
  558   
  559           public Map.Entry<K,V> next() {
  560               if (!hasNext())
  561                   throw new NoSuchElementException();
  562               lastReturnedEntry = new Entry(index++);
  563               return lastReturnedEntry;
  564           }
  565   
  566           public void remove() {
  567               lastReturnedIndex =
  568                   ((null == lastReturnedEntry) ? -1 : lastReturnedEntry.index);
  569               super.remove();
  570               lastReturnedEntry.index = lastReturnedIndex;
  571               lastReturnedEntry = null;
  572           }
  573   
  574           private class Entry implements Map.Entry<K,V> {
  575               private int index;
  576   
  577               private Entry(int index) {
  578                   this.index = index;
  579               }
  580   
  581               public K getKey() {
  582                   checkIndexForEntryUse();
  583                   return keyUniverse[index];
  584               }
  585   
  586               public V getValue() {
  587                   checkIndexForEntryUse();
  588                   return unmaskNull(vals[index]);
  589               }
  590   
  591               public V setValue(V value) {
  592                   checkIndexForEntryUse();
  593                   V oldValue = unmaskNull(vals[index]);
  594                   vals[index] = maskNull(value);
  595                   return oldValue;
  596               }
  597   
  598               public boolean equals(Object o) {
  599                   if (index < 0)
  600                       return o == this;
  601   
  602                   if (!(o instanceof Map.Entry))
  603                       return false;
  604   
  605                   Map.Entry e = (Map.Entry)o;
  606                   V ourValue = unmaskNull(vals[index]);
  607                   Object hisValue = e.getValue();
  608                   return (e.getKey() == keyUniverse[index] &&
  609                           (ourValue == hisValue ||
  610                            (ourValue != null && ourValue.equals(hisValue))));
  611               }
  612   
  613               public int hashCode() {
  614                   if (index < 0)
  615                       return super.hashCode();
  616   
  617                   return entryHashCode(index);
  618               }
  619   
  620               public String toString() {
  621                   if (index < 0)
  622                       return super.toString();
  623   
  624                   return keyUniverse[index] + "="
  625                       + unmaskNull(vals[index]);
  626               }
  627   
  628               private void checkIndexForEntryUse() {
  629                   if (index < 0)
  630                       throw new IllegalStateException("Entry was removed");
  631               }
  632           }
  633       }
  634   
  635       // Comparison and hashing
  636   
  637       /**
  638        * Compares the specified object with this map for equality.  Returns
  639        * <tt>true</tt> if the given object is also a map and the two maps
  640        * represent the same mappings, as specified in the {@link
  641        * Map#equals(Object)} contract.
  642        *
  643        * @param o the object to be compared for equality with this map
  644        * @return <tt>true</tt> if the specified object is equal to this map
  645        */
  646       public boolean equals(Object o) {
  647           if (this == o)
  648               return true;
  649           if (o instanceof EnumMap)
  650               return equals((EnumMap)o);
  651           if (!(o instanceof Map))
  652               return false;
  653   
  654           Map<K,V> m = (Map<K,V>)o;
  655           if (size != m.size())
  656               return false;
  657   
  658           for (int i = 0; i < keyUniverse.length; i++) {
  659               if (null != vals[i]) {
  660                   K key = keyUniverse[i];
  661                   V value = unmaskNull(vals[i]);
  662                   if (null == value) {
  663                       if (!((null == m.get(key)) && m.containsKey(key)))
  664                          return false;
  665                   } else {
  666                      if (!value.equals(m.get(key)))
  667                         return false;
  668                   }
  669               }
  670           }
  671   
  672           return true;
  673       }
  674   
  675       private boolean equals(EnumMap em) {
  676           if (em.keyType != keyType)
  677               return size == 0 && em.size == 0;
  678   
  679           // Key types match, compare each value
  680           for (int i = 0; i < keyUniverse.length; i++) {
  681               Object ourValue =    vals[i];
  682               Object hisValue = em.vals[i];
  683               if (hisValue != ourValue &&
  684                   (hisValue == null || !hisValue.equals(ourValue)))
  685                   return false;
  686           }
  687           return true;
  688       }
  689   
  690       /**
  691        * Returns the hash code value for this map.  The hash code of a map is
  692        * defined to be the sum of the hash codes of each entry in the map.
  693        */
  694       public int hashCode() {
  695           int h = 0;
  696   
  697           for (int i = 0; i < keyUniverse.length; i++) {
  698               if (null != vals[i]) {
  699                   h += entryHashCode(i);
  700               }
  701           }
  702   
  703           return h;
  704       }
  705   
  706       private int entryHashCode(int index) {
  707           return (keyUniverse[index].hashCode() ^ vals[index].hashCode());
  708       }
  709   
  710       /**
  711        * Returns a shallow copy of this enum map.  (The values themselves
  712        * are not cloned.
  713        *
  714        * @return a shallow copy of this enum map
  715        */
  716       public EnumMap<K, V> clone() {
  717           EnumMap<K, V> result = null;
  718           try {
  719               result = (EnumMap<K, V>) super.clone();
  720           } catch(CloneNotSupportedException e) {
  721               throw new AssertionError();
  722           }
  723           result.vals = result.vals.clone();
  724           return result;
  725       }
  726   
  727       /**
  728        * Throws an exception if e is not of the correct type for this enum set.
  729        */
  730       private void typeCheck(K key) {
  731           Class keyClass = key.getClass();
  732           if (keyClass != keyType && keyClass.getSuperclass() != keyType)
  733               throw new ClassCastException(keyClass + " != " + keyType);
  734       }
  735   
  736       /**
  737        * Returns all of the values comprising K.
  738        * The result is uncloned, cached, and shared by all callers.
  739        */
  740       private static <K extends Enum<K>> K[] getKeyUniverse(Class<K> keyType) {
  741           return SharedSecrets.getJavaLangAccess()
  742                                           .getEnumConstantsShared(keyType);
  743       }
  744   
  745       private static final long serialVersionUID = 458661240069192865L;
  746   
  747       /**
  748        * Save the state of the <tt>EnumMap</tt> instance to a stream (i.e.,
  749        * serialize it).
  750        *
  751        * @serialData The <i>size</i> of the enum map (the number of key-value
  752        *             mappings) is emitted (int), followed by the key (Object)
  753        *             and value (Object) for each key-value mapping represented
  754        *             by the enum map.
  755        */
  756       private void writeObject(java.io.ObjectOutputStream s)
  757           throws java.io.IOException
  758       {
  759           // Write out the key type and any hidden stuff
  760           s.defaultWriteObject();
  761   
  762           // Write out size (number of Mappings)
  763           s.writeInt(size);
  764   
  765           // Write out keys and values (alternating)
  766           int entriesToBeWritten = size;
  767           for (int i = 0; entriesToBeWritten > 0; i++) {
  768               if (null != vals[i]) {
  769                   s.writeObject(keyUniverse[i]);
  770                   s.writeObject(unmaskNull(vals[i]));
  771                   entriesToBeWritten--;
  772               }
  773           }
  774       }
  775   
  776       /**
  777        * Reconstitute the <tt>EnumMap</tt> instance from a stream (i.e.,
  778        * deserialize it).
  779        */
  780       private void readObject(java.io.ObjectInputStream s)
  781           throws java.io.IOException, ClassNotFoundException
  782       {
  783           // Read in the key type and any hidden stuff
  784           s.defaultReadObject();
  785   
  786           keyUniverse = getKeyUniverse(keyType);
  787           vals = new Object[keyUniverse.length];
  788   
  789           // Read in size (number of Mappings)
  790           int size = s.readInt();
  791   
  792           // Read the keys and values, and put the mappings in the HashMap
  793           for (int i = 0; i < size; i++) {
  794               K key = (K) s.readObject();
  795               V value = (V) s.readObject();
  796               put(key, value);
  797           }
  798       }
  799   }

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