001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.collections.map;
018
019 import java.io.IOException;
020 import java.io.ObjectInputStream;
021 import java.io.ObjectOutputStream;
022 import java.io.Serializable;
023 import java.util.Map;
024
025 /**
026 * A <code>Map</code> implementation that matches keys and values based
027 * on <code>==</code> not <code>equals()</code>.
028 * <p>
029 * This map will violate the detail of various Map and map view contracts.
030 * As a general rule, don't compare this map to other maps.
031 * <p>
032 * <strong>Note that IdentityMap is not synchronized and is not thread-safe.</strong>
033 * If you wish to use this map from multiple threads concurrently, you must use
034 * appropriate synchronization. The simplest approach is to wrap this map
035 * using {@link java.util.Collections#synchronizedMap(Map)}. This class may throw
036 * exceptions when accessed by concurrent threads without synchronization.
037 *
038 * @since Commons Collections 3.0
039 * @version $Revision: 646777 $ $Date: 2008-04-10 13:33:15 +0100 (Thu, 10 Apr 2008) $
040 *
041 * @author java util HashMap
042 * @author Stephen Colebourne
043 */
044 public class IdentityMap
045 extends AbstractHashedMap implements Serializable, Cloneable {
046
047 /** Serialisation version */
048 private static final long serialVersionUID = 2028493495224302329L;
049
050 /**
051 * Constructs a new empty map with default size and load factor.
052 */
053 public IdentityMap() {
054 super(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_THRESHOLD);
055 }
056
057 /**
058 * Constructs a new, empty map with the specified initial capacity.
059 *
060 * @param initialCapacity the initial capacity
061 * @throws IllegalArgumentException if the initial capacity is less than one
062 */
063 public IdentityMap(int initialCapacity) {
064 super(initialCapacity);
065 }
066
067 /**
068 * Constructs a new, empty map with the specified initial capacity and
069 * load factor.
070 *
071 * @param initialCapacity the initial capacity
072 * @param loadFactor the load factor
073 * @throws IllegalArgumentException if the initial capacity is less than one
074 * @throws IllegalArgumentException if the load factor is less than zero
075 */
076 public IdentityMap(int initialCapacity, float loadFactor) {
077 super(initialCapacity, loadFactor);
078 }
079
080 /**
081 * Constructor copying elements from another map.
082 *
083 * @param map the map to copy
084 * @throws NullPointerException if the map is null
085 */
086 public IdentityMap(Map map) {
087 super(map);
088 }
089
090 //-----------------------------------------------------------------------
091 /**
092 * Gets the hash code for the key specified.
093 * This implementation uses the identity hash code.
094 *
095 * @param key the key to get a hash code for
096 * @return the hash code
097 */
098 protected int hash(Object key) {
099 return System.identityHashCode(key);
100 }
101
102 /**
103 * Compares two keys for equals.
104 * This implementation uses <code>==</code>.
105 *
106 * @param key1 the first key to compare
107 * @param key2 the second key to compare
108 * @return true if equal by identity
109 */
110 protected boolean isEqualKey(Object key1, Object key2) {
111 return (key1 == key2);
112 }
113
114 /**
115 * Compares two values for equals.
116 * This implementation uses <code>==</code>.
117 *
118 * @param value1 the first value to compare
119 * @param value2 the second value to compare
120 * @return true if equal by identity
121 */
122 protected boolean isEqualValue(Object value1, Object value2) {
123 return (value1 == value2);
124 }
125
126 /**
127 * Creates an entry to store the data.
128 * This implementation creates an IdentityEntry instance.
129 *
130 * @param next the next entry in sequence
131 * @param hashCode the hash code to use
132 * @param key the key to store
133 * @param value the value to store
134 * @return the newly created entry
135 */
136 protected HashEntry createEntry(HashEntry next, int hashCode, Object key, Object value) {
137 return new IdentityEntry(next, hashCode, key, value);
138 }
139
140 //-----------------------------------------------------------------------
141 /**
142 * HashEntry
143 */
144 protected static class IdentityEntry extends HashEntry {
145
146 protected IdentityEntry(HashEntry next, int hashCode, Object key, Object value) {
147 super(next, hashCode, key, value);
148 }
149
150 public boolean equals(Object obj) {
151 if (obj == this) {
152 return true;
153 }
154 if (obj instanceof Map.Entry == false) {
155 return false;
156 }
157 Map.Entry other = (Map.Entry) obj;
158 return
159 (getKey() == other.getKey()) &&
160 (getValue() == other.getValue());
161 }
162
163 public int hashCode() {
164 return System.identityHashCode(getKey()) ^
165 System.identityHashCode(getValue());
166 }
167 }
168
169 //-----------------------------------------------------------------------
170 /**
171 * Clones the map without cloning the keys or values.
172 *
173 * @return a shallow clone
174 */
175 public Object clone() {
176 return super.clone();
177 }
178
179 /**
180 * Write the map out using a custom routine.
181 */
182 private void writeObject(ObjectOutputStream out) throws IOException {
183 out.defaultWriteObject();
184 doWriteObject(out);
185 }
186
187 /**
188 * Read the map in using a custom routine.
189 */
190 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
191 in.defaultReadObject();
192 doReadObject(in);
193 }
194
195 }