LinkedHashMap.java revision 0
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk/*
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Copyright 1998-2000 Sun Microsystems, Inc. All Rights Reserved.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk *
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * This code is free software; you can redistribute it and/or modify it
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * under the terms of the GNU General Public License version 2 only, as
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * published by the Free Software Foundation. Sun designates this
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * particular file as subject to the "Classpath" exception as provided
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * by Sun in the LICENSE file that accompanied this code.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk *
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * This code is distributed in the hope that it will be useful, but WITHOUT
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * version 2 for more details (a copy is included in the LICENSE file that
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * accompanied this code).
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk *
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * You should have received a copy of the GNU General Public License version
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * 2 along with this work; if not, write to the Free Software Foundation,
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk *
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * CA 95054 USA or visit www.sun.com if you need additional information or
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * have any questions.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenkpackage com.sun.tools.jdi;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenkimport java.io.*;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenkimport java.util.*;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk/**
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Hash table based implementation of the Map interface. This implementation
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * provides all of the optional Map operations, and permits null values and
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * the null key. (HashMap is roughly equivalent to Hashtable, except that it
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * is unsynchronized and permits nulls.) In addition, elements in the map are
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * ordered and doubly linked together.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * <p>
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * This implementation provides constant-time performance for the basic
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * operations (get and put), assuming the the hash function disperses the
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * elements properly among the buckets. Iteration over Collection views
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * requires time proportional to its size (the number of key-value mappings)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * and returns elements in the order they are linked. In a HashMap the
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * iteration would require time proportional to the capacity of the map
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * plus the map size.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * <p>
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * An instance of LinkedHashMap has two parameters that affect its efficiency:
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * its <i>capacity</i> and its <i>load factor</i>. The load factor should be
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * between 0.0 and 1.0. When the number of mappings in the LinkedHashMap exceeds
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * the product of the load factor and the current capacity, the capacity is
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * increased by calling the rehash method which requires time proportional
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * to the number of key-value mappings in the map. Larger load factors
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * use memory more efficiently, at the expense of larger expected time per
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * lookup.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * <p>
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * If many mappings are to be stored in a LinkedHashMap, creating it with a
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * sufficiently large capacity will allow the mappings to be stored more
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * efficiently than letting it perform automatic rehashing as needed to grow
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * the table.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * <p>
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * <strong>Note that this implementation is not synchronized.</strong> If
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * multiple threads access a LinkedHashMap concurrently, and at least one of the
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * threads modifies the LinkedHashMap structurally, it <em>must</em> be
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * synchronized externally. (A structural modification is any operation that
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * adds or deletes one or more mappings; merely changing the value associated
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * with a key that is already contained in the Table is not a structural
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * modification.) This is typically accomplished by synchronizing on some
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * object that naturally encapsulates the LinkedHashMap. If no such object
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * exists, the LinkedHashMap should be "wrapped" using the
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Collections.synchronizedSet method. This is best done at creation time, to
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * prevent accidental unsynchronized access to the LinkedHashMap:
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * <pre>
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Map m = Collections.synchronizedMap(new LinkedHashMap(...));
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * </pre>
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * <p>
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * The Iterators returned by the iterator methods of the Collections returned
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * by all of LinkedHashMap's "collection view methods" are <em>fail-fast</em>:
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * if the LinkedHashMap is structurally modified at any time after the Iterator
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * is created, in any way except through the Iterator's own remove or add
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * methods, the Iterator will throw a ConcurrentModificationException. Thus,
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * in the face of concurrent modification, the Iterator fails quickly and
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * cleanly, rather than risking arbitrary, non-deterministic behavior at an
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * undetermined time in the future.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk *
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * @author Josh Bloch
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * @author Arthur van Hoff
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * @author Zhenghua Li
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * @see Object#hashCode()
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * @see java.util.Collection
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * @see java.util.Map
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * @see java.util.TreeMap
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * @see java.util.Hashtable
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * @see java.util.HashMap
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenkimport java.io.Serializable;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenkpublic class LinkedHashMap extends AbstractMap implements Map, Serializable {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /**
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * The hash table data.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk private transient Entry table[];
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /**
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * The head of the double linked list.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk private transient Entry header;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /**
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * The total number of mappings in the hash table.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk private transient int count;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /**
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Rehashes the table when count exceeds this threshold.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk private int threshold;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /**
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * The load factor for the LinkedHashMap.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk private float loadFactor;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /**
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * The number of times this LinkedHashMap has been structurally modified
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Structural modifications are those that change the number of mappings in
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * the LinkedHashMap or otherwise modify its internal structure (e.g.,
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * rehash). This field is used to make iterators on Collection-views of
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * the LinkedHashMap fail-fast. (See ConcurrentModificationException).
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk private transient int modCount = 0;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /**
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Constructs a new, empty LinkedHashMap with the specified initial
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * capacity and the specified load factor.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk *
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * @param initialCapacity the initial capacity of the LinkedHashMap.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * @param loadFactor a number between 0.0 and 1.0.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * @exception IllegalArgumentException if the initial capacity is less
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * than or equal to zero, or if the load factor is less than
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * or equal to zero.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk public LinkedHashMap(int initialCapacity, float loadFactor) {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (initialCapacity < 0)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk throw new IllegalArgumentException("Illegal Initial Capacity: "+
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk initialCapacity);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if ((loadFactor > 1) || (loadFactor <= 0))
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk throw new IllegalArgumentException("Illegal Load factor: "+
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk loadFactor);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (initialCapacity==0)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk initialCapacity = 1;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk this.loadFactor = loadFactor;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk table = new Entry[initialCapacity];
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk threshold = (int)(initialCapacity * loadFactor);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk header = new Entry(-1, null, null, null);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk header.before = header.after = header;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /**
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Constructs a new, empty LinkedHashMap with the specified initial capacity
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * and default load factor.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk *
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * @param initialCapacity the initial capacity of the LinkedHashMap.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk public LinkedHashMap(int initialCapacity) {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk this(initialCapacity, 0.75f);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /**
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Constructs a new, empty LinkedHashMap with a default capacity and load
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * factor.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk public LinkedHashMap() {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk this(101, 0.75f);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /**
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Constructs a new LinkedHashMap with the same mappings as the given
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Map. The LinkedHashMap is created with a capacity of thrice the number
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * of mappings in the given Map or 11 (whichever is greater), and a
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * default load factor.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk public LinkedHashMap(Map t) {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk this(Math.max(3*t.size(), 11), 0.75f);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk putAll(t);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /**
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Returns the number of key-value mappings in this Map.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk public int size() {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return count;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /**
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Returns true if this Map contains no key-value mappings.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk public boolean isEmpty() {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return count == 0;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /**
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Returns true if this LinkedHashMap maps one or more keys to the specified
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * value.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk *
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * @param value value whose presence in this Map is to be tested.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk public boolean containsValue(Object value) {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (value==null) {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk for (Entry e = header.after; e != header; e = e.after)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (e.value==null)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return true;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk } else {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk for (Entry e = header.after; e != header; e = e.after)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (value.equals(e.value))
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return true;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return false;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /**
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Returns true if this LinkedHashMap contains a mapping for the specified
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * key.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk *
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * @param key key whose presence in this Map is to be tested.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk public boolean containsKey(Object key) {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk Entry tab[] = table;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (key != null) {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk int hash = key.hashCode();
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk int index = (hash & 0x7FFFFFFF) % tab.length;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk for (Entry e = tab[index]; e != null; e = e.next)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (e.hash==hash && e.key.equals(key))
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return true;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk } else {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk for (Entry e = tab[0]; e != null; e = e.next)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (e.key==null)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return true;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return false;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /**
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Returns the value to which this LinkedHashMap maps the specified key.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Returns null if the LinkedHashMap contains no mapping for this key.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * A return value of null does not <em>necessarily</em> indicate that the
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * LinkedHashMap contains no mapping for the key; it's also possible that
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * the LinkedHashMap explicitly maps the key to null. The containsKey
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * operation may be used to distinguish these two cases.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk *
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * @param key key whose associated value is to be returned.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk public Object get(Object key) {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk Entry e = getEntry(key);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return e==null ? null : e.value;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /**
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Returns the entry associated with the specified key in the LinkedHashMap.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Returns null if the LinkedHashMap contains no mapping for this key.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk private Entry getEntry(Object key) {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk Entry tab[] = table;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (key != null) {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk int hash = key.hashCode();
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk int index = (hash & 0x7FFFFFFF) % tab.length;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk for (Entry e = tab[index]; e != null; e = e.next)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if ((e.hash == hash) && e.key.equals(key))
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return e;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk } else {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk for (Entry e = tab[0]; e != null; e = e.next)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (e.key==null)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return e;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return null;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /**
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Rehashes the contents of the LinkedHashMap into a LinkedHashMap with a
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * larger capacity. This method is called automatically when the
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * number of keys in the LinkedHashMap exceeds this LinkedHashMap's capacity
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * and load factor.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk private void rehash() {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk int oldCapacity = table.length;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk Entry oldMap[] = table;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk int newCapacity = oldCapacity * 2 + 1;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk Entry newMap[] = new Entry[newCapacity];
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk modCount++;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk threshold = (int)(newCapacity * loadFactor);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk table = newMap;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk for (Entry e = header.after; e != header; e = e.after) {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk int index = (e.hash & 0x7FFFFFFF) % newCapacity;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk e.next = newMap[index];
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk newMap[index] = e;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /**
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Remove an entry from the linked list.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk private void listRemove(Entry entry) {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (entry == null) {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk entry.before.after = entry.after;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk entry.after.before = entry.before;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /**
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Add the specified entry before the specified existing entry to
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * the linked list.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk private void listAddBefore(Entry entry, Entry existEntry) {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk entry.after = existEntry;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk entry.before = existEntry.before;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk entry.before.after = entry;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk entry.after.before = entry;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk }
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /**
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Returns the position of the mapping for the specified key
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * in the ordered map.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk *
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * @param key the specified key.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * @return index of the key mapping.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk public int indexOf(Object key) {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk int i = 0;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (key == null) {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk for (Entry e = header.after; e != header; e = e.after, i++)
if (e.key == null)
return i;
} else {
for (Entry e = header.after; e != header; e = e.after, i++)
if(key.equals(e.key))
return i;
}
return -1;
}
/**
* Associates the specified value with the specified key in this
* LinkedHashMap. If the LinkedHashMap previously contained a mapping for
* this key, the old value is replaced and the position of this mapping
* entry in the double linked list remains the same. Otherwise, a new
* mapping entry is created and inserted into the list before the specified
* existing mapping entry. The method returns the previous value associated
* with the specified key, or null if there was no mapping for key. A null
* return can also indicate that the LinkedHashMap previously associated
* null with the specified key.
*/
private Object putAhead(Object key, Object value, Entry existEntry) {
// Makes sure the key is not already in the LinkedHashMap.
Entry tab[] = table;
int hash = 0;
int index = 0;
if (key != null) {
hash = key.hashCode();
index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
Object old = e.value;
e.value = value;
return old;
}
}
} else {
for (Entry e = tab[0] ; e != null ; e = e.next) {
if (e.key == null) {
Object old = e.value;
e.value = value;
return old;
}
}
}
modCount++;
if (count >= threshold) {
// Rehash the table if the threshold is exceeded
rehash();
tab = table;
index = (hash & 0x7FFFFFFF) % tab.length;
}
// Creates the new entry.
Entry e = new Entry(hash, key, value, tab[index]);
tab[index] = e;
listAddBefore(e, existEntry);
count++;
return null;
}
/**
* Associates the specified value with the specified key in this
* LinkedHashMap and position the mapping at the specified index.
* If the LinkedHashMap previously contained a mapping for this key,
* the old value is replaced and the position of this mapping entry
* in the double linked list remains the same. Otherwise, a new mapping
* entry is created and inserted into the list at the specified
* position.
*
* @param index the position to put the key-value mapping.
* @param key key with which the specified value is to be associated.
* @param value value to be associated with the specified key.
* @return previous value associated with specified key, or null if there
* was no mapping for key. A null return can also indicate that
* the LinkedHashMap previously associated null with the specified
* key.
*/
public Object put(int index, Object key, Object value) {
if (index < 0 || index > count)
throw new IndexOutOfBoundsException();
Entry e = header.after;
if (index == count)
return putAhead(key, value, header); //fast approach for append
else {
for (int i = 0; i < index; i++)
e = e.after;
return putAhead(key, value, e);
}
}
/**
* Associates the specified value with the specified key in this
* LinkedHashMap. If the LinkedHashMap previously contained a mapping for
* this key, the old value is replaced. The mapping entry is also appended
* to the end of the ordered linked list.
*
* @param key key with which the specified value is to be associated.
* @param value value to be associated with the specified key.
* @return previous value associated with specified key, or null if there
* was no mapping for key. A null return can also indicate that
* the LinkedHashMap previously associated null with the specified
* key.
*/
public Object put(Object key, Object value) {
return putAhead(key, value, header);
}
/**
* Removes the mapping for this key from this LinkedHashMap if present.
* The mapping would also be removed from the double linked list.
*
* @param key key whose mapping is to be removed from the Map.
* @return previous value associated with specified key, or null if there
* was no mapping for key. A null return can also indicate that
* the LinkedHashMap previously associated null with the specified
* key.
*/
public Object remove(Object key) {
Entry tab[] = table;
if (key != null) {
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry e = tab[index], prev = null; e != null;
prev = e, e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
modCount++;
if (prev != null)
prev.next = e.next;
else
tab[index] = e.next;
count--;
Object oldValue = e.value;
e.value = null;
listRemove(e);
return oldValue;
}
}
} else {
for (Entry e = tab[0], prev = null; e != null;
prev = e, e = e.next) {
if (e.key == null) {
modCount++;
if (prev != null)
prev.next = e.next;
else
tab[0] = e.next;
count--;
Object oldValue = e.value;
e.value = null;
listRemove(e);
return oldValue;
}
}
}
return null;
}
/**
* Copies all of the mappings from the specified Map to this LinkedHashMap
* These mappings will replace any mappings that this LinkedHashMap had for
* any of the keys currently in the specified Map.
*
* @param t Mappings to be stored in this Map.
*/
public void putAll(Map t) {
Iterator i = t.entrySet().iterator();
while (i.hasNext()) {
Map.Entry e = (Map.Entry) i.next();
put(e.getKey(), e.getValue());
}
}
/**
* Removes all mappings from this LinkedHashMap.
*/
public void clear() {
Entry tab[] = table;
modCount++;
for (int index = tab.length; --index >= 0; )
tab[index] = null;
count = 0;
header.before = header.after = header;
}
/**
* Returns a shallow copy of this LinkedHashMap. The keys and values
* themselves are not cloned.
*/
public Object clone() {
return new LinkedHashMap(this);
}
// Views
private transient Set keySet = null;
private transient Set entries = null;
private transient Collection values = null;
/**
* Returns a Set view of the keys contained in this LinkedHashMap. The Set
* is backed by the LinkedHashMap, so changes to the LinkedHashMap are
* reflected in the Set, and vice-versa. The Set supports element removal,
* which removes the corresponding mapping from the LinkedHashMap, via the
* Iterator.remove, Set.remove, removeAll retainAll, and clear operations.
* It does not support the add or addAll operations.
*/
public Set keySet() {
if (keySet == null) {
keySet = new AbstractSet() {
public Iterator iterator() {
return new HashIterator(KEYS);
}
public int size() {
return count;
}
public boolean contains(Object o) {
return containsKey(o);
}
public boolean remove(Object o) {
return LinkedHashMap.this.remove(o) != null;
}
public void clear() {
LinkedHashMap.this.clear();
}
};
}
return keySet;
}
/**
* Returns a Collection view of the values contained in this LinkedHashMap.
* The Collection is backed by the LinkedHashMap, so changes to the
* LinkedHashMap are reflected in the Collection, and vice-versa. The
* Collection supports element removal, which removes the corresponding
* mapping from the LinkedHashMap, via the Iterator.remove,
* Collection.remove, removeAll, retainAll and clear operations. It does
* not support the add or addAll operations.
*/
public Collection values() {
if (values==null) {
values = new AbstractCollection() {
public Iterator iterator() {
return new HashIterator(VALUES);
}
public int size() {
return count;
}
public boolean contains(Object o) {
return containsValue(o);
}
public void clear() {
LinkedHashMap.this.clear();
}
};
}
return values;
}
/**
* Returns a Collection view of the mappings contained in this
* LinkedHashMap. Each element in the returned collection is a Map.Entry.
* The Collection is backed by the LinkedHashMap, so changes to the
* LinkedHashMap are reflected in the Collection, and vice-versa. The
* Collection supports element removal, which removes the corresponding
* mapping from the LinkedHashMap, via the Iterator.remove,
* Collection.remove, removeAll, retainAll and clear operations. It does
* not support the add or addAll operations.
*
* @see java.util.Map.Entry
*/
public Set entrySet() {
if (entries==null) {
entries = new AbstractSet() {
public Iterator iterator() {
return new HashIterator(ENTRIES);
}
public boolean contains(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry entry = (Map.Entry)o;
Object key = entry.getKey();
Entry tab[] = table;
int hash = (key==null ? 0 : key.hashCode());
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry e = tab[index]; e != null; e = e.next)
if (e.hash==hash && e.equals(entry))
return true;
return false;
}
public boolean remove(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry entry = (Map.Entry)o;
Object key = entry.getKey();
Entry tab[] = table;
int hash = (key==null ? 0 : key.hashCode());
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry e = tab[index], prev = null; e != null;
prev = e, e = e.next) {
if (e.hash==hash && e.equals(entry)) {
modCount++;
if (prev != null)
prev.next = e.next;
else
tab[index] = e.next;
count--;
e.value = null;
listRemove(e);
return true;
}
}
return false;
}
public int size() {
return count;
}
public void clear() {
LinkedHashMap.this.clear();
}
};
}
return entries;
}
/**
* Compares the specified Object with this Map for equality.
* Returns true if the given object is also a LinkedHashMap and the two
* Maps represent the same mappings in the same order. More formally,
* two Maps <code>t1</code> and <code>t2</code> represent the same mappings
* if <code>t1.keySet().equals(t2.keySet())</code> and for every
* key <code>k</code> in <code>t1.keySet()</code>, <code>
* (t1.get(k)==null ? t2.get(k)==null : t1.get(k).equals(t2.get(k)))
* </code>.
* <p>
* This implementation first checks if the specified Object is this Map;
* if so it returns true. Then, it checks if the specified Object is
* a Map whose size is identical to the size of this Set; if not, it
* it returns false. If so, it iterates over this Map and the specified
* Map's entrySet() Collection, and checks that the specified Map contains
* each mapping that this Map contains at the same position. If the
* specified Map fails to contain such a mapping in the right order, false
* is returned. If the iteration completes, true is returned.
*
* @param o Object to be compared for equality with this Map.
* @return true if the specified Object is equal to this Map.
*
*/
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof LinkedHashMap))
return false;
LinkedHashMap t = (LinkedHashMap) o;
if (t.size() != size())
return false;
Iterator i1 = entrySet().iterator();
Iterator i2 = t.entrySet().iterator();
while (i1.hasNext()) {
Entry e1 = (Entry) i1.next();
Entry e2 = (Entry) i2.next();
Object key1 = e1.getKey();
Object value1 = e1.getValue();
Object key2 = e2.getKey();
Object value2 = e2.getValue();
if ((key1 == null ? key2 == null : key1.equals(key2)) &&
(value1 == null ? value2 == null : value1.equals(value2))) {
continue;
} else {
return false;
}
}
return true;
}
/**
* LinkedHashMap collision list entry.
*/
private static class Entry implements Map.Entry {
int hash;
Object key;
Object value;
Entry next;
// These fields comprise the doubly linked list that is used for
// iteration.
Entry before, after;
Entry(int hash, Object key, Object value, Entry next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
// Map.Entry Ops
public Object getKey() {
return key;
}
public Object getValue() {
return value;
}
public Object setValue(Object value) {
Object oldValue = this.value;
this.value = value;
return oldValue;
}
public boolean equals(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry e = (Map.Entry)o;
return (key==null ? e.getKey()==null : key.equals(e.getKey())) &&
(value==null ? e.getValue()==null : value.equals(e.getValue()));
}
public int hashCode() {
return hash ^ (value==null ? 0 : value.hashCode());
}
public String toString() {
return key+"="+value;
}
}
// Types of Iterators
private static final int KEYS = 0;
private static final int VALUES = 1;
private static final int ENTRIES = 2;
private class HashIterator implements Iterator {
private Entry[] table = LinkedHashMap.this.table;
private Entry entry = null;
private Entry lastReturned = null;
private int type;
/**
* The modCount value that the iterator believes that the backing
* List should have. If this expectation is violated, the iterator
* has detected concurrent modification.
*/
private int expectedModCount = modCount;
HashIterator(int type) {
this.type = type;
this.entry = LinkedHashMap.this.header.after;
}
public boolean hasNext() {
return entry != header;
}
public Object next() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (entry == LinkedHashMap.this.header)
throw new NoSuchElementException();
Entry e = lastReturned = entry;
entry = e.after;
return type == KEYS ? e.key : (type == VALUES ? e.value : e);
}
public void remove() {
if (lastReturned == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
Entry[] tab = LinkedHashMap.this.table;
int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length;
for (Entry e = tab[index], prev = null; e != null;
prev = e, e = e.next) {
if (e == lastReturned) {
modCount++;
expectedModCount++;
if (prev == null)
tab[index] = e.next;
else
prev.next = e.next;
count--;
listRemove(e);
lastReturned = null;
return;
}
}
throw new ConcurrentModificationException();
}
}
/**
* Save the state of the LinkedHashMap to a stream (i.e., serialize it).
* The objects will be written out in the order they are linked
* in the list.
*/
private void writeObject(java.io.ObjectOutputStream s)
throws IOException
{
// Write out the threshold, loadfactor, and any hidden stuff
s.defaultWriteObject();
// Write out number of buckets
s.writeInt(table.length);
// Write out size (number of Mappings)
s.writeInt(count);
// Write out keys and values (alternating)
for (Entry e = header.after; e != header; e = e.after) {
s.writeObject(e.key);
s.writeObject(e.value);
}
}
/**
* Reconstitute the LinkedHashMap from a stream (i.e., deserialize it).
*/
private void readObject(java.io.ObjectInputStream s)
throws IOException, ClassNotFoundException
{
// Read in the threshold, loadfactor, and any hidden stuff
s.defaultReadObject();
// Read in number of buckets and allocate the bucket array;
int numBuckets = s.readInt();
table = new Entry[numBuckets];
header = new Entry(-1, null, null, null);
header.before = header;
header.after = header;
// Read in size (number of Mappings)
int size = s.readInt();
// Read the keys and values, and put the mappings in the LinkedHashMap
for (int i=0; i<size; i++) {
Object key = s.readObject();
Object value = s.readObject();
put(key, value);
}
}
}