jaroslav@557: /* jaroslav@557: * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. jaroslav@557: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. jaroslav@557: * jaroslav@557: * This code is free software; you can redistribute it and/or modify it jaroslav@557: * under the terms of the GNU General Public License version 2 only, as jaroslav@557: * published by the Free Software Foundation. Oracle designates this jaroslav@557: * particular file as subject to the "Classpath" exception as provided jaroslav@557: * by Oracle in the LICENSE file that accompanied this code. jaroslav@557: * jaroslav@557: * This code is distributed in the hope that it will be useful, but WITHOUT jaroslav@557: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or jaroslav@557: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License jaroslav@557: * version 2 for more details (a copy is included in the LICENSE file that jaroslav@557: * accompanied this code). jaroslav@557: * jaroslav@557: * You should have received a copy of the GNU General Public License version jaroslav@557: * 2 along with this work; if not, write to the Free Software Foundation, jaroslav@557: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. jaroslav@557: * jaroslav@557: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA jaroslav@557: * or visit www.oracle.com if you need additional information or have any jaroslav@557: * questions. jaroslav@557: */ jaroslav@557: jaroslav@557: package java.util; jaroslav@557: import java.util.Map.Entry; jaroslav@557: jaroslav@557: /** jaroslav@557: * This class provides a skeletal implementation of the Map jaroslav@557: * interface, to minimize the effort required to implement this interface. jaroslav@557: * jaroslav@557: *

To implement an unmodifiable map, the programmer needs only to extend this jaroslav@557: * class and provide an implementation for the entrySet method, which jaroslav@557: * returns a set-view of the map's mappings. Typically, the returned set jaroslav@557: * will, in turn, be implemented atop AbstractSet. This set should jaroslav@557: * not support the add or remove methods, and its iterator jaroslav@557: * should not support the remove method. jaroslav@557: * jaroslav@557: *

To implement a modifiable map, the programmer must additionally override jaroslav@557: * this class's put method (which otherwise throws an jaroslav@557: * UnsupportedOperationException), and the iterator returned by jaroslav@557: * entrySet().iterator() must additionally implement its jaroslav@557: * remove method. jaroslav@557: * jaroslav@557: *

The programmer should generally provide a void (no argument) and map jaroslav@557: * constructor, as per the recommendation in the Map interface jaroslav@557: * specification. jaroslav@557: * jaroslav@557: *

The documentation for each non-abstract method in this class describes its jaroslav@557: * implementation in detail. Each of these methods may be overridden if the jaroslav@557: * map being implemented admits a more efficient implementation. jaroslav@557: * jaroslav@557: *

This class is a member of the jaroslav@557: * jaroslav@557: * Java Collections Framework. jaroslav@557: * jaroslav@557: * @param the type of keys maintained by this map jaroslav@557: * @param the type of mapped values jaroslav@557: * jaroslav@557: * @author Josh Bloch jaroslav@557: * @author Neal Gafter jaroslav@557: * @see Map jaroslav@557: * @see Collection jaroslav@557: * @since 1.2 jaroslav@557: */ jaroslav@557: jaroslav@557: public abstract class AbstractMap implements Map { jaroslav@557: /** jaroslav@557: * Sole constructor. (For invocation by subclass constructors, typically jaroslav@557: * implicit.) jaroslav@557: */ jaroslav@557: protected AbstractMap() { jaroslav@557: } jaroslav@557: jaroslav@557: // Query Operations jaroslav@557: jaroslav@557: /** jaroslav@557: * {@inheritDoc} jaroslav@557: * jaroslav@557: *

This implementation returns entrySet().size(). jaroslav@557: */ jaroslav@557: public int size() { jaroslav@557: return entrySet().size(); jaroslav@557: } jaroslav@557: jaroslav@557: /** jaroslav@557: * {@inheritDoc} jaroslav@557: * jaroslav@557: *

This implementation returns size() == 0. jaroslav@557: */ jaroslav@557: public boolean isEmpty() { jaroslav@557: return size() == 0; jaroslav@557: } jaroslav@557: jaroslav@557: /** jaroslav@557: * {@inheritDoc} jaroslav@557: * jaroslav@557: *

This implementation iterates over entrySet() searching jaroslav@557: * for an entry with the specified value. If such an entry is found, jaroslav@557: * true is returned. If the iteration terminates without jaroslav@557: * finding such an entry, false is returned. Note that this jaroslav@557: * implementation requires linear time in the size of the map. jaroslav@557: * jaroslav@557: * @throws ClassCastException {@inheritDoc} jaroslav@557: * @throws NullPointerException {@inheritDoc} jaroslav@557: */ jaroslav@557: public boolean containsValue(Object value) { jaroslav@557: Iterator> i = entrySet().iterator(); jaroslav@557: if (value==null) { jaroslav@557: while (i.hasNext()) { jaroslav@557: Entry e = i.next(); jaroslav@557: if (e.getValue()==null) jaroslav@557: return true; jaroslav@557: } jaroslav@557: } else { jaroslav@557: while (i.hasNext()) { jaroslav@557: Entry e = i.next(); jaroslav@557: if (value.equals(e.getValue())) jaroslav@557: return true; jaroslav@557: } jaroslav@557: } jaroslav@557: return false; jaroslav@557: } jaroslav@557: jaroslav@557: /** jaroslav@557: * {@inheritDoc} jaroslav@557: * jaroslav@557: *

This implementation iterates over entrySet() searching jaroslav@557: * for an entry with the specified key. If such an entry is found, jaroslav@557: * true is returned. If the iteration terminates without jaroslav@557: * finding such an entry, false is returned. Note that this jaroslav@557: * implementation requires linear time in the size of the map; many jaroslav@557: * implementations will override this method. jaroslav@557: * jaroslav@557: * @throws ClassCastException {@inheritDoc} jaroslav@557: * @throws NullPointerException {@inheritDoc} jaroslav@557: */ jaroslav@557: public boolean containsKey(Object key) { jaroslav@557: Iterator> i = entrySet().iterator(); jaroslav@557: if (key==null) { jaroslav@557: while (i.hasNext()) { jaroslav@557: Entry e = i.next(); jaroslav@557: if (e.getKey()==null) jaroslav@557: return true; jaroslav@557: } jaroslav@557: } else { jaroslav@557: while (i.hasNext()) { jaroslav@557: Entry e = i.next(); jaroslav@557: if (key.equals(e.getKey())) jaroslav@557: return true; jaroslav@557: } jaroslav@557: } jaroslav@557: return false; jaroslav@557: } jaroslav@557: jaroslav@557: /** jaroslav@557: * {@inheritDoc} jaroslav@557: * jaroslav@557: *

This implementation iterates over entrySet() searching jaroslav@557: * for an entry with the specified key. If such an entry is found, jaroslav@557: * the entry's value is returned. If the iteration terminates without jaroslav@557: * finding such an entry, null is returned. Note that this jaroslav@557: * implementation requires linear time in the size of the map; many jaroslav@557: * implementations will override this method. jaroslav@557: * jaroslav@557: * @throws ClassCastException {@inheritDoc} jaroslav@557: * @throws NullPointerException {@inheritDoc} jaroslav@557: */ jaroslav@557: public V get(Object key) { jaroslav@557: Iterator> i = entrySet().iterator(); jaroslav@557: if (key==null) { jaroslav@557: while (i.hasNext()) { jaroslav@557: Entry e = i.next(); jaroslav@557: if (e.getKey()==null) jaroslav@557: return e.getValue(); jaroslav@557: } jaroslav@557: } else { jaroslav@557: while (i.hasNext()) { jaroslav@557: Entry e = i.next(); jaroslav@557: if (key.equals(e.getKey())) jaroslav@557: return e.getValue(); jaroslav@557: } jaroslav@557: } jaroslav@557: return null; jaroslav@557: } jaroslav@557: jaroslav@557: jaroslav@557: // Modification Operations jaroslav@557: jaroslav@557: /** jaroslav@557: * {@inheritDoc} jaroslav@557: * jaroslav@557: *

This implementation always throws an jaroslav@557: * UnsupportedOperationException. jaroslav@557: * jaroslav@557: * @throws UnsupportedOperationException {@inheritDoc} jaroslav@557: * @throws ClassCastException {@inheritDoc} jaroslav@557: * @throws NullPointerException {@inheritDoc} jaroslav@557: * @throws IllegalArgumentException {@inheritDoc} jaroslav@557: */ jaroslav@557: public V put(K key, V value) { jaroslav@557: throw new UnsupportedOperationException(); jaroslav@557: } jaroslav@557: jaroslav@557: /** jaroslav@557: * {@inheritDoc} jaroslav@557: * jaroslav@557: *

This implementation iterates over entrySet() searching for an jaroslav@557: * entry with the specified key. If such an entry is found, its value is jaroslav@557: * obtained with its getValue operation, the entry is removed jaroslav@557: * from the collection (and the backing map) with the iterator's jaroslav@557: * remove operation, and the saved value is returned. If the jaroslav@557: * iteration terminates without finding such an entry, null is jaroslav@557: * returned. Note that this implementation requires linear time in the jaroslav@557: * size of the map; many implementations will override this method. jaroslav@557: * jaroslav@557: *

Note that this implementation throws an jaroslav@557: * UnsupportedOperationException if the entrySet jaroslav@557: * iterator does not support the remove method and this map jaroslav@557: * contains a mapping for the specified key. jaroslav@557: * jaroslav@557: * @throws UnsupportedOperationException {@inheritDoc} jaroslav@557: * @throws ClassCastException {@inheritDoc} jaroslav@557: * @throws NullPointerException {@inheritDoc} jaroslav@557: */ jaroslav@557: public V remove(Object key) { jaroslav@557: Iterator> i = entrySet().iterator(); jaroslav@557: Entry correctEntry = null; jaroslav@557: if (key==null) { jaroslav@557: while (correctEntry==null && i.hasNext()) { jaroslav@557: Entry e = i.next(); jaroslav@557: if (e.getKey()==null) jaroslav@557: correctEntry = e; jaroslav@557: } jaroslav@557: } else { jaroslav@557: while (correctEntry==null && i.hasNext()) { jaroslav@557: Entry e = i.next(); jaroslav@557: if (key.equals(e.getKey())) jaroslav@557: correctEntry = e; jaroslav@557: } jaroslav@557: } jaroslav@557: jaroslav@557: V oldValue = null; jaroslav@557: if (correctEntry !=null) { jaroslav@557: oldValue = correctEntry.getValue(); jaroslav@557: i.remove(); jaroslav@557: } jaroslav@557: return oldValue; jaroslav@557: } jaroslav@557: jaroslav@557: jaroslav@557: // Bulk Operations jaroslav@557: jaroslav@557: /** jaroslav@557: * {@inheritDoc} jaroslav@557: * jaroslav@557: *

This implementation iterates over the specified map's jaroslav@557: * entrySet() collection, and calls this map's put jaroslav@557: * operation once for each entry returned by the iteration. jaroslav@557: * jaroslav@557: *

Note that this implementation throws an jaroslav@557: * UnsupportedOperationException if this map does not support jaroslav@557: * the put operation and the specified map is nonempty. jaroslav@557: * jaroslav@557: * @throws UnsupportedOperationException {@inheritDoc} jaroslav@557: * @throws ClassCastException {@inheritDoc} jaroslav@557: * @throws NullPointerException {@inheritDoc} jaroslav@557: * @throws IllegalArgumentException {@inheritDoc} jaroslav@557: */ jaroslav@557: public void putAll(Map m) { jaroslav@557: for (Map.Entry e : m.entrySet()) jaroslav@557: put(e.getKey(), e.getValue()); jaroslav@557: } jaroslav@557: jaroslav@557: /** jaroslav@557: * {@inheritDoc} jaroslav@557: * jaroslav@557: *

This implementation calls entrySet().clear(). jaroslav@557: * jaroslav@557: *

Note that this implementation throws an jaroslav@557: * UnsupportedOperationException if the entrySet jaroslav@557: * does not support the clear operation. jaroslav@557: * jaroslav@557: * @throws UnsupportedOperationException {@inheritDoc} jaroslav@557: */ jaroslav@557: public void clear() { jaroslav@557: entrySet().clear(); jaroslav@557: } jaroslav@557: jaroslav@557: jaroslav@557: // Views jaroslav@557: jaroslav@557: /** jaroslav@557: * Each of these fields are initialized to contain an instance of the jaroslav@557: * appropriate view the first time this view is requested. The views are jaroslav@557: * stateless, so there's no reason to create more than one of each. jaroslav@557: */ jaroslav@557: transient volatile Set keySet = null; jaroslav@557: transient volatile Collection values = null; jaroslav@557: jaroslav@557: /** jaroslav@557: * {@inheritDoc} jaroslav@557: * jaroslav@557: *

This implementation returns a set that subclasses {@link AbstractSet}. jaroslav@557: * The subclass's iterator method returns a "wrapper object" over this jaroslav@557: * map's entrySet() iterator. The size method jaroslav@557: * delegates to this map's size method and the jaroslav@557: * contains method delegates to this map's jaroslav@557: * containsKey method. jaroslav@557: * jaroslav@557: *

The set is created the first time this method is called, jaroslav@557: * and returned in response to all subsequent calls. No synchronization jaroslav@557: * is performed, so there is a slight chance that multiple calls to this jaroslav@557: * method will not all return the same set. jaroslav@557: */ jaroslav@557: public Set keySet() { jaroslav@557: if (keySet == null) { jaroslav@557: keySet = new AbstractSet() { jaroslav@557: public Iterator iterator() { jaroslav@557: return new Iterator() { jaroslav@557: private Iterator> i = entrySet().iterator(); jaroslav@557: jaroslav@557: public boolean hasNext() { jaroslav@557: return i.hasNext(); jaroslav@557: } jaroslav@557: jaroslav@557: public K next() { jaroslav@557: return i.next().getKey(); jaroslav@557: } jaroslav@557: jaroslav@557: public void remove() { jaroslav@557: i.remove(); jaroslav@557: } jaroslav@557: }; jaroslav@557: } jaroslav@557: jaroslav@557: public int size() { jaroslav@557: return AbstractMap.this.size(); jaroslav@557: } jaroslav@557: jaroslav@557: public boolean isEmpty() { jaroslav@557: return AbstractMap.this.isEmpty(); jaroslav@557: } jaroslav@557: jaroslav@557: public void clear() { jaroslav@557: AbstractMap.this.clear(); jaroslav@557: } jaroslav@557: jaroslav@557: public boolean contains(Object k) { jaroslav@557: return AbstractMap.this.containsKey(k); jaroslav@557: } jaroslav@557: }; jaroslav@557: } jaroslav@557: return keySet; jaroslav@557: } jaroslav@557: jaroslav@557: /** jaroslav@557: * {@inheritDoc} jaroslav@557: * jaroslav@557: *

This implementation returns a collection that subclasses {@link jaroslav@557: * AbstractCollection}. The subclass's iterator method returns a jaroslav@557: * "wrapper object" over this map's entrySet() iterator. jaroslav@557: * The size method delegates to this map's size jaroslav@557: * method and the contains method delegates to this map's jaroslav@557: * containsValue method. jaroslav@557: * jaroslav@557: *

The collection is created the first time this method is called, and jaroslav@557: * returned in response to all subsequent calls. No synchronization is jaroslav@557: * performed, so there is a slight chance that multiple calls to this jaroslav@557: * method will not all return the same collection. jaroslav@557: */ jaroslav@557: public Collection values() { jaroslav@557: if (values == null) { jaroslav@557: values = new AbstractCollection() { jaroslav@557: public Iterator iterator() { jaroslav@557: return new Iterator() { jaroslav@557: private Iterator> i = entrySet().iterator(); jaroslav@557: jaroslav@557: public boolean hasNext() { jaroslav@557: return i.hasNext(); jaroslav@557: } jaroslav@557: jaroslav@557: public V next() { jaroslav@557: return i.next().getValue(); jaroslav@557: } jaroslav@557: jaroslav@557: public void remove() { jaroslav@557: i.remove(); jaroslav@557: } jaroslav@557: }; jaroslav@557: } jaroslav@557: jaroslav@557: public int size() { jaroslav@557: return AbstractMap.this.size(); jaroslav@557: } jaroslav@557: jaroslav@557: public boolean isEmpty() { jaroslav@557: return AbstractMap.this.isEmpty(); jaroslav@557: } jaroslav@557: jaroslav@557: public void clear() { jaroslav@557: AbstractMap.this.clear(); jaroslav@557: } jaroslav@557: jaroslav@557: public boolean contains(Object v) { jaroslav@557: return AbstractMap.this.containsValue(v); jaroslav@557: } jaroslav@557: }; jaroslav@557: } jaroslav@557: return values; jaroslav@557: } jaroslav@557: jaroslav@557: public abstract Set> entrySet(); jaroslav@557: jaroslav@557: jaroslav@557: // Comparison and hashing jaroslav@557: jaroslav@557: /** jaroslav@557: * Compares the specified object with this map for equality. Returns jaroslav@557: * true if the given object is also a map and the two maps jaroslav@557: * represent the same mappings. More formally, two maps m1 and jaroslav@557: * m2 represent the same mappings if jaroslav@557: * m1.entrySet().equals(m2.entrySet()). This ensures that the jaroslav@557: * equals method works properly across different implementations jaroslav@557: * of the Map interface. jaroslav@557: * jaroslav@557: *

This implementation first checks if the specified object is this map; jaroslav@557: * if so it returns true. Then, it checks if the specified jaroslav@557: * object is a map whose size is identical to the size of this map; if jaroslav@557: * not, it returns false. If so, it iterates over this map's jaroslav@557: * entrySet collection, and checks that the specified map jaroslav@557: * contains each mapping that this map contains. If the specified map jaroslav@557: * fails to contain such a mapping, false is returned. If the jaroslav@557: * iteration completes, true is returned. jaroslav@557: * jaroslav@557: * @param o object to be compared for equality with this map jaroslav@557: * @return true if the specified object is equal to this map jaroslav@557: */ jaroslav@557: public boolean equals(Object o) { jaroslav@557: if (o == this) jaroslav@557: return true; jaroslav@557: jaroslav@557: if (!(o instanceof Map)) jaroslav@557: return false; jaroslav@557: Map m = (Map) o; jaroslav@557: if (m.size() != size()) jaroslav@557: return false; jaroslav@557: jaroslav@557: try { jaroslav@557: Iterator> i = entrySet().iterator(); jaroslav@557: while (i.hasNext()) { jaroslav@557: Entry e = i.next(); jaroslav@557: K key = e.getKey(); jaroslav@557: V value = e.getValue(); jaroslav@557: if (value == null) { jaroslav@557: if (!(m.get(key)==null && m.containsKey(key))) jaroslav@557: return false; jaroslav@557: } else { jaroslav@557: if (!value.equals(m.get(key))) jaroslav@557: return false; jaroslav@557: } jaroslav@557: } jaroslav@557: } catch (ClassCastException unused) { jaroslav@557: return false; jaroslav@557: } catch (NullPointerException unused) { jaroslav@557: return false; jaroslav@557: } jaroslav@557: jaroslav@557: return true; jaroslav@557: } jaroslav@557: jaroslav@557: /** jaroslav@557: * Returns the hash code value for this map. The hash code of a map is jaroslav@557: * defined to be the sum of the hash codes of each entry in the map's jaroslav@557: * entrySet() view. This ensures that m1.equals(m2) jaroslav@557: * implies that m1.hashCode()==m2.hashCode() for any two maps jaroslav@557: * m1 and m2, as required by the general contract of jaroslav@557: * {@link Object#hashCode}. jaroslav@557: * jaroslav@557: *

This implementation iterates over entrySet(), calling jaroslav@557: * {@link Map.Entry#hashCode hashCode()} on each element (entry) in the jaroslav@557: * set, and adding up the results. jaroslav@557: * jaroslav@557: * @return the hash code value for this map jaroslav@557: * @see Map.Entry#hashCode() jaroslav@557: * @see Object#equals(Object) jaroslav@557: * @see Set#equals(Object) jaroslav@557: */ jaroslav@557: public int hashCode() { jaroslav@557: int h = 0; jaroslav@557: Iterator> i = entrySet().iterator(); jaroslav@557: while (i.hasNext()) jaroslav@557: h += i.next().hashCode(); jaroslav@557: return h; jaroslav@557: } jaroslav@557: jaroslav@557: /** jaroslav@557: * Returns a string representation of this map. The string representation jaroslav@557: * consists of a list of key-value mappings in the order returned by the jaroslav@557: * map's entrySet view's iterator, enclosed in braces jaroslav@557: * ("{}"). Adjacent mappings are separated by the characters jaroslav@557: * ", " (comma and space). Each key-value mapping is rendered as jaroslav@557: * the key followed by an equals sign ("=") followed by the jaroslav@557: * associated value. Keys and values are converted to strings as by jaroslav@557: * {@link String#valueOf(Object)}. jaroslav@557: * jaroslav@557: * @return a string representation of this map jaroslav@557: */ jaroslav@557: public String toString() { jaroslav@557: Iterator> i = entrySet().iterator(); jaroslav@557: if (! i.hasNext()) jaroslav@557: return "{}"; jaroslav@557: jaroslav@557: StringBuilder sb = new StringBuilder(); jaroslav@557: sb.append('{'); jaroslav@557: for (;;) { jaroslav@557: Entry e = i.next(); jaroslav@557: K key = e.getKey(); jaroslav@557: V value = e.getValue(); jaroslav@557: sb.append(key == this ? "(this Map)" : key); jaroslav@557: sb.append('='); jaroslav@557: sb.append(value == this ? "(this Map)" : value); jaroslav@557: if (! i.hasNext()) jaroslav@557: return sb.append('}').toString(); jaroslav@557: sb.append(',').append(' '); jaroslav@557: } jaroslav@557: } jaroslav@557: jaroslav@557: /** jaroslav@557: * Returns a shallow copy of this AbstractMap instance: the keys jaroslav@557: * and values themselves are not cloned. jaroslav@557: * jaroslav@557: * @return a shallow copy of this map jaroslav@557: */ jaroslav@557: protected Object clone() throws CloneNotSupportedException { jaroslav@557: AbstractMap result = (AbstractMap)super.clone(); jaroslav@557: result.keySet = null; jaroslav@557: result.values = null; jaroslav@557: return result; jaroslav@557: } jaroslav@557: jaroslav@557: /** jaroslav@557: * Utility method for SimpleEntry and SimpleImmutableEntry. jaroslav@557: * Test for equality, checking for nulls. jaroslav@557: */ jaroslav@557: private static boolean eq(Object o1, Object o2) { jaroslav@557: return o1 == null ? o2 == null : o1.equals(o2); jaroslav@557: } jaroslav@557: jaroslav@557: // Implementation Note: SimpleEntry and SimpleImmutableEntry jaroslav@557: // are distinct unrelated classes, even though they share jaroslav@557: // some code. Since you can't add or subtract final-ness jaroslav@557: // of a field in a subclass, they can't share representations, jaroslav@557: // and the amount of duplicated code is too small to warrant jaroslav@557: // exposing a common abstract class. jaroslav@557: jaroslav@557: jaroslav@557: /** jaroslav@557: * An Entry maintaining a key and a value. The value may be jaroslav@557: * changed using the setValue method. This class jaroslav@557: * facilitates the process of building custom map jaroslav@557: * implementations. For example, it may be convenient to return jaroslav@557: * arrays of SimpleEntry instances in method jaroslav@557: * Map.entrySet().toArray. jaroslav@557: * jaroslav@557: * @since 1.6 jaroslav@557: */ jaroslav@557: public static class SimpleEntry jaroslav@557: implements Entry, java.io.Serializable jaroslav@557: { jaroslav@557: private static final long serialVersionUID = -8499721149061103585L; jaroslav@557: jaroslav@557: private final K key; jaroslav@557: private V value; jaroslav@557: jaroslav@557: /** jaroslav@557: * Creates an entry representing a mapping from the specified jaroslav@557: * key to the specified value. jaroslav@557: * jaroslav@557: * @param key the key represented by this entry jaroslav@557: * @param value the value represented by this entry jaroslav@557: */ jaroslav@557: public SimpleEntry(K key, V value) { jaroslav@557: this.key = key; jaroslav@557: this.value = value; jaroslav@557: } jaroslav@557: jaroslav@557: /** jaroslav@557: * Creates an entry representing the same mapping as the jaroslav@557: * specified entry. jaroslav@557: * jaroslav@557: * @param entry the entry to copy jaroslav@557: */ jaroslav@557: public SimpleEntry(Entry entry) { jaroslav@557: this.key = entry.getKey(); jaroslav@557: this.value = entry.getValue(); jaroslav@557: } jaroslav@557: jaroslav@557: /** jaroslav@557: * Returns the key corresponding to this entry. jaroslav@557: * jaroslav@557: * @return the key corresponding to this entry jaroslav@557: */ jaroslav@557: public K getKey() { jaroslav@557: return key; jaroslav@557: } jaroslav@557: jaroslav@557: /** jaroslav@557: * Returns the value corresponding to this entry. jaroslav@557: * jaroslav@557: * @return the value corresponding to this entry jaroslav@557: */ jaroslav@557: public V getValue() { jaroslav@557: return value; jaroslav@557: } jaroslav@557: jaroslav@557: /** jaroslav@557: * Replaces the value corresponding to this entry with the specified jaroslav@557: * value. jaroslav@557: * jaroslav@557: * @param value new value to be stored in this entry jaroslav@557: * @return the old value corresponding to the entry jaroslav@557: */ jaroslav@557: public V setValue(V value) { jaroslav@557: V oldValue = this.value; jaroslav@557: this.value = value; jaroslav@557: return oldValue; jaroslav@557: } jaroslav@557: jaroslav@557: /** jaroslav@557: * Compares the specified object with this entry for equality. jaroslav@557: * Returns {@code true} if the given object is also a map entry and jaroslav@557: * the two entries represent the same mapping. More formally, two jaroslav@557: * entries {@code e1} and {@code e2} represent the same mapping jaroslav@557: * if

jaroslav@557:          *   (e1.getKey()==null ?
jaroslav@557:          *    e2.getKey()==null :
jaroslav@557:          *    e1.getKey().equals(e2.getKey()))
jaroslav@557:          *   &&
jaroslav@557:          *   (e1.getValue()==null ?
jaroslav@557:          *    e2.getValue()==null :
jaroslav@557:          *    e1.getValue().equals(e2.getValue()))
jaroslav@557: * This ensures that the {@code equals} method works properly across jaroslav@557: * different implementations of the {@code Map.Entry} interface. jaroslav@557: * jaroslav@557: * @param o object to be compared for equality with this map entry jaroslav@557: * @return {@code true} if the specified object is equal to this map jaroslav@557: * entry jaroslav@557: * @see #hashCode jaroslav@557: */ jaroslav@557: public boolean equals(Object o) { jaroslav@557: if (!(o instanceof Map.Entry)) jaroslav@557: return false; jaroslav@557: Map.Entry e = (Map.Entry)o; jaroslav@557: return eq(key, e.getKey()) && eq(value, e.getValue()); jaroslav@557: } jaroslav@557: jaroslav@557: /** jaroslav@557: * Returns the hash code value for this map entry. The hash code jaroslav@557: * of a map entry {@code e} is defined to be:
jaroslav@557:          *   (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
jaroslav@557:          *   (e.getValue()==null ? 0 : e.getValue().hashCode())
jaroslav@557: * This ensures that {@code e1.equals(e2)} implies that jaroslav@557: * {@code e1.hashCode()==e2.hashCode()} for any two Entries jaroslav@557: * {@code e1} and {@code e2}, as required by the general jaroslav@557: * contract of {@link Object#hashCode}. jaroslav@557: * jaroslav@557: * @return the hash code value for this map entry jaroslav@557: * @see #equals jaroslav@557: */ jaroslav@557: public int hashCode() { jaroslav@557: return (key == null ? 0 : key.hashCode()) ^ jaroslav@557: (value == null ? 0 : value.hashCode()); jaroslav@557: } jaroslav@557: jaroslav@557: /** jaroslav@557: * Returns a String representation of this map entry. This jaroslav@557: * implementation returns the string representation of this jaroslav@557: * entry's key followed by the equals character ("=") jaroslav@557: * followed by the string representation of this entry's value. jaroslav@557: * jaroslav@557: * @return a String representation of this map entry jaroslav@557: */ jaroslav@557: public String toString() { jaroslav@557: return key + "=" + value; jaroslav@557: } jaroslav@557: jaroslav@557: } jaroslav@557: jaroslav@557: /** jaroslav@557: * An Entry maintaining an immutable key and value. This class jaroslav@557: * does not support method setValue. This class may be jaroslav@557: * convenient in methods that return thread-safe snapshots of jaroslav@557: * key-value mappings. jaroslav@557: * jaroslav@557: * @since 1.6 jaroslav@557: */ jaroslav@557: public static class SimpleImmutableEntry jaroslav@557: implements Entry, java.io.Serializable jaroslav@557: { jaroslav@557: private static final long serialVersionUID = 7138329143949025153L; jaroslav@557: jaroslav@557: private final K key; jaroslav@557: private final V value; jaroslav@557: jaroslav@557: /** jaroslav@557: * Creates an entry representing a mapping from the specified jaroslav@557: * key to the specified value. jaroslav@557: * jaroslav@557: * @param key the key represented by this entry jaroslav@557: * @param value the value represented by this entry jaroslav@557: */ jaroslav@557: public SimpleImmutableEntry(K key, V value) { jaroslav@557: this.key = key; jaroslav@557: this.value = value; jaroslav@557: } jaroslav@557: jaroslav@557: /** jaroslav@557: * Creates an entry representing the same mapping as the jaroslav@557: * specified entry. jaroslav@557: * jaroslav@557: * @param entry the entry to copy jaroslav@557: */ jaroslav@557: public SimpleImmutableEntry(Entry entry) { jaroslav@557: this.key = entry.getKey(); jaroslav@557: this.value = entry.getValue(); jaroslav@557: } jaroslav@557: jaroslav@557: /** jaroslav@557: * Returns the key corresponding to this entry. jaroslav@557: * jaroslav@557: * @return the key corresponding to this entry jaroslav@557: */ jaroslav@557: public K getKey() { jaroslav@557: return key; jaroslav@557: } jaroslav@557: jaroslav@557: /** jaroslav@557: * Returns the value corresponding to this entry. jaroslav@557: * jaroslav@557: * @return the value corresponding to this entry jaroslav@557: */ jaroslav@557: public V getValue() { jaroslav@557: return value; jaroslav@557: } jaroslav@557: jaroslav@557: /** jaroslav@557: * Replaces the value corresponding to this entry with the specified jaroslav@557: * value (optional operation). This implementation simply throws jaroslav@557: * UnsupportedOperationException, as this class implements jaroslav@557: * an immutable map entry. jaroslav@557: * jaroslav@557: * @param value new value to be stored in this entry jaroslav@557: * @return (Does not return) jaroslav@557: * @throws UnsupportedOperationException always jaroslav@557: */ jaroslav@557: public V setValue(V value) { jaroslav@557: throw new UnsupportedOperationException(); jaroslav@557: } jaroslav@557: jaroslav@557: /** jaroslav@557: * Compares the specified object with this entry for equality. jaroslav@557: * Returns {@code true} if the given object is also a map entry and jaroslav@557: * the two entries represent the same mapping. More formally, two jaroslav@557: * entries {@code e1} and {@code e2} represent the same mapping jaroslav@557: * if
jaroslav@557:          *   (e1.getKey()==null ?
jaroslav@557:          *    e2.getKey()==null :
jaroslav@557:          *    e1.getKey().equals(e2.getKey()))
jaroslav@557:          *   &&
jaroslav@557:          *   (e1.getValue()==null ?
jaroslav@557:          *    e2.getValue()==null :
jaroslav@557:          *    e1.getValue().equals(e2.getValue()))
jaroslav@557: * This ensures that the {@code equals} method works properly across jaroslav@557: * different implementations of the {@code Map.Entry} interface. jaroslav@557: * jaroslav@557: * @param o object to be compared for equality with this map entry jaroslav@557: * @return {@code true} if the specified object is equal to this map jaroslav@557: * entry jaroslav@557: * @see #hashCode jaroslav@557: */ jaroslav@557: public boolean equals(Object o) { jaroslav@557: if (!(o instanceof Map.Entry)) jaroslav@557: return false; jaroslav@557: Map.Entry e = (Map.Entry)o; jaroslav@557: return eq(key, e.getKey()) && eq(value, e.getValue()); jaroslav@557: } jaroslav@557: jaroslav@557: /** jaroslav@557: * Returns the hash code value for this map entry. The hash code jaroslav@557: * of a map entry {@code e} is defined to be:
jaroslav@557:          *   (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
jaroslav@557:          *   (e.getValue()==null ? 0 : e.getValue().hashCode())
jaroslav@557: * This ensures that {@code e1.equals(e2)} implies that jaroslav@557: * {@code e1.hashCode()==e2.hashCode()} for any two Entries jaroslav@557: * {@code e1} and {@code e2}, as required by the general jaroslav@557: * contract of {@link Object#hashCode}. jaroslav@557: * jaroslav@557: * @return the hash code value for this map entry jaroslav@557: * @see #equals jaroslav@557: */ jaroslav@557: public int hashCode() { jaroslav@557: return (key == null ? 0 : key.hashCode()) ^ jaroslav@557: (value == null ? 0 : value.hashCode()); jaroslav@557: } jaroslav@557: jaroslav@557: /** jaroslav@557: * Returns a String representation of this map entry. This jaroslav@557: * implementation returns the string representation of this jaroslav@557: * entry's key followed by the equals character ("=") jaroslav@557: * followed by the string representation of this entry's value. jaroslav@557: * jaroslav@557: * @return a String representation of this map entry jaroslav@557: */ jaroslav@557: public String toString() { jaroslav@557: return key + "=" + value; jaroslav@557: } jaroslav@557: jaroslav@557: } jaroslav@557: jaroslav@557: }