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