1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.collections.map;
18
19 import java.io.IOException;
20 import java.io.ObjectInputStream;
21 import java.io.ObjectOutputStream;
22 import java.io.Serializable;
23 import java.util.Map;
24
25 /**
26 * A <code>Map</code> implementation that matches keys and values based
27 * on <code>==</code> not <code>equals()</code>.
28 * <p>
29 * <strong>This map will violate the detail of various Map and map view contracts.</note>
30 * As a general rule, don't compare this map to other maps. In particular, you can't
31 * use decorators like {@link ListOrderedMap} on it, which silently assume that these
32 * contracts are fulfilled.
33 * <p>
34 * <strong>Note that IdentityMap is not synchronized and is not thread-safe.</strong>
35 * If you wish to use this map from multiple threads concurrently, you must use
36 * appropriate synchronization. The simplest approach is to wrap this map
37 * using {@link java.util.Collections#synchronizedMap(Map)}. This class may throw
38 * exceptions when accessed by concurrent threads without synchronization.
39 *
40 * @since 3.0
41 * @version $Id: IdentityMap.java 1435824 2013-01-20 11:41:17Z tn $
42 */
43 public class IdentityMap<K, V>
44 extends AbstractHashedMap<K, V> implements Serializable, Cloneable {
45
46 /** Serialisation version */
47 private static final long serialVersionUID = 2028493495224302329L;
48
49 /**
50 * Constructs a new empty map with default size and load factor.
51 */
52 public IdentityMap() {
53 super(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_THRESHOLD);
54 }
55
56 /**
57 * Constructs a new, empty map with the specified initial capacity.
58 *
59 * @param initialCapacity the initial capacity
60 * @throws IllegalArgumentException if the initial capacity is negative
61 */
62 public IdentityMap(final int initialCapacity) {
63 super(initialCapacity);
64 }
65
66 /**
67 * Constructs a new, empty map with the specified initial capacity and
68 * load factor.
69 *
70 * @param initialCapacity the initial capacity
71 * @param loadFactor the load factor
72 * @throws IllegalArgumentException if the initial capacity is negative
73 * @throws IllegalArgumentException if the load factor is less than zero
74 */
75 public IdentityMap(final int initialCapacity, final float loadFactor) {
76 super(initialCapacity, loadFactor);
77 }
78
79 /**
80 * Constructor copying elements from another map.
81 *
82 * @param map the map to copy
83 * @throws NullPointerException if the map is null
84 */
85 public IdentityMap(final Map<K, V> map) {
86 super(map);
87 }
88
89 //-----------------------------------------------------------------------
90 /**
91 * Gets the hash code for the key specified.
92 * This implementation uses the identity hash code.
93 *
94 * @param key the key to get a hash code for
95 * @return the hash code
96 */
97 @Override
98 protected int hash(final Object key) {
99 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 @Override
111 protected boolean isEqualKey(final Object key1, final Object key2) {
112 return key1 == key2;
113 }
114
115 /**
116 * Compares two values for equals.
117 * This implementation uses <code>==</code>.
118 *
119 * @param value1 the first value to compare
120 * @param value2 the second value to compare
121 * @return true if equal by identity
122 */
123 @Override
124 protected boolean isEqualValue(final Object value1, final Object value2) {
125 return value1 == value2;
126 }
127
128 /**
129 * Creates an entry to store the data.
130 * This implementation creates an IdentityEntry instance.
131 *
132 * @param next the next entry in sequence
133 * @param hashCode the hash code to use
134 * @param key the key to store
135 * @param value the value to store
136 * @return the newly created entry
137 */
138 @Override
139 protected IdentityEntry<K, V> createEntry(final HashEntry<K, V> next, final int hashCode,
140 final K key, final V value) {
141 return new IdentityEntry<K, V>(next, hashCode, key, value);
142 }
143
144 //-----------------------------------------------------------------------
145 /**
146 * HashEntry
147 */
148 protected static class IdentityEntry<K, V> extends HashEntry<K, V> {
149
150 protected IdentityEntry(final HashEntry<K, V> next, final int hashCode, final K key, final V value) {
151 super(next, hashCode, key, value);
152 }
153
154 @Override
155 public boolean equals(final Object obj) {
156 if (obj == this) {
157 return true;
158 }
159 if (obj instanceof Map.Entry == false) {
160 return false;
161 }
162 final Map.Entry<?, ?> other = (Map.Entry<?, ?>) obj;
163 return
164 getKey() == other.getKey() &&
165 getValue() == other.getValue();
166 }
167
168 @Override
169 public int hashCode() {
170 return System.identityHashCode(getKey()) ^
171 System.identityHashCode(getValue());
172 }
173 }
174
175 //-----------------------------------------------------------------------
176 /**
177 * Clones the map without cloning the keys or values.
178 *
179 * @return a shallow clone
180 */
181 @Override
182 public IdentityMap<K, V> clone() {
183 return (IdentityMap<K, V>) super.clone();
184 }
185
186 /**
187 * Write the map out using a custom routine.
188 */
189 private void writeObject(final ObjectOutputStream out) throws IOException {
190 out.defaultWriteObject();
191 doWriteObject(out);
192 }
193
194 /**
195 * Read the map in using a custom routine.
196 */
197 private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
198 in.defaultReadObject();
199 doReadObject(in);
200 }
201
202 }