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.lang.ref.Reference;
024
025 /**
026 * A <code>Map</code> implementation that allows mappings to be
027 * removed by the garbage collector and matches keys and values based
028 * on <code>==</code> not <code>equals()</code>.
029 * <p>
030 * <p>
031 * When you construct a <code>ReferenceIdentityMap</code>, you can specify what kind
032 * of references are used to store the map's keys and values.
033 * If non-hard references are used, then the garbage collector can remove
034 * mappings if a key or value becomes unreachable, or if the JVM's memory is
035 * running low. For information on how the different reference types behave,
036 * see {@link Reference}.
037 * <p>
038 * Different types of references can be specified for keys and values.
039 * The default constructor uses hard keys and soft values, providing a
040 * memory-sensitive cache.
041 * <p>
042 * This map is similar to
043 * {@link org.apache.commons.collections.map.ReferenceMap ReferenceMap}.
044 * It differs in that keys and values in this class are compared using <code>==</code>.
045 * <p>
046 * This map will violate the detail of various Map and map view contracts.
047 * As a general rule, don't compare this map to other maps.
048 * <p>
049 * This {@link java.util.Map Map} implementation does <i>not</i> allow null elements.
050 * Attempting to add a null key or value to the map will raise a <code>NullPointerException</code>.
051 * <p>
052 * This implementation is not synchronized.
053 * You can use {@link java.util.Collections#synchronizedMap} to
054 * provide synchronized access to a <code>ReferenceIdentityMap</code>.
055 * Remember that synchronization will not stop the garbage collecter removing entries.
056 * <p>
057 * All the available iterators can be reset back to the start by casting to
058 * <code>ResettableIterator</code> and calling <code>reset()</code>.
059 * <p>
060 * <strong>Note that ReferenceIdentityMap is not synchronized and is not thread-safe.</strong>
061 * If you wish to use this map from multiple threads concurrently, you must use
062 * appropriate synchronization. The simplest approach is to wrap this map
063 * using {@link java.util.Collections#synchronizedMap}. This class may throw
064 * exceptions when accessed by concurrent threads without synchronization.
065 *
066 * @see java.lang.ref.Reference
067 *
068 * @since Commons Collections 3.0 (previously in main package v2.1)
069 * @version $Revision: 646777 $ $Date: 2008-04-10 13:33:15 +0100 (Thu, 10 Apr 2008) $
070 *
071 * @author Stephen Colebourne
072 */
073 public class ReferenceIdentityMap extends AbstractReferenceMap implements Serializable {
074
075 /** Serialization version */
076 private static final long serialVersionUID = -1266190134568365852L;
077
078 /**
079 * Constructs a new <code>ReferenceIdentityMap</code> that will
080 * use hard references to keys and soft references to values.
081 */
082 public ReferenceIdentityMap() {
083 super(HARD, SOFT, DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, false);
084 }
085
086 /**
087 * Constructs a new <code>ReferenceIdentityMap</code> that will
088 * use the specified types of references.
089 *
090 * @param keyType the type of reference to use for keys;
091 * must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
092 * @param valueType the type of reference to use for values;
093 * must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
094 */
095 public ReferenceIdentityMap(int keyType, int valueType) {
096 super(keyType, valueType, DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, false);
097 }
098
099 /**
100 * Constructs a new <code>ReferenceIdentityMap</code> that will
101 * use the specified types of references.
102 *
103 * @param keyType the type of reference to use for keys;
104 * must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
105 * @param valueType the type of reference to use for values;
106 * must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
107 * @param purgeValues should the value be automatically purged when the
108 * key is garbage collected
109 */
110 public ReferenceIdentityMap(int keyType, int valueType, boolean purgeValues) {
111 super(keyType, valueType, DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, purgeValues);
112 }
113
114 /**
115 * Constructs a new <code>ReferenceIdentityMap</code> with the
116 * specified reference types, load factor and initial capacity.
117 *
118 * @param keyType the type of reference to use for keys;
119 * must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
120 * @param valueType the type of reference to use for values;
121 * must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
122 * @param capacity the initial capacity for the map
123 * @param loadFactor the load factor for the map
124 */
125 public ReferenceIdentityMap(int keyType, int valueType, int capacity, float loadFactor) {
126 super(keyType, valueType, capacity, loadFactor, false);
127 }
128
129 /**
130 * Constructs a new <code>ReferenceIdentityMap</code> with the
131 * specified reference types, load factor and initial capacity.
132 *
133 * @param keyType the type of reference to use for keys;
134 * must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
135 * @param valueType the type of reference to use for values;
136 * must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
137 * @param capacity the initial capacity for the map
138 * @param loadFactor the load factor for the map
139 * @param purgeValues should the value be automatically purged when the
140 * key is garbage collected
141 */
142 public ReferenceIdentityMap(int keyType, int valueType, int capacity,
143 float loadFactor, boolean purgeValues) {
144 super(keyType, valueType, capacity, loadFactor, purgeValues);
145 }
146
147 //-----------------------------------------------------------------------
148 /**
149 * Gets the hash code for the key specified.
150 * <p>
151 * This implementation uses the identity hash code.
152 *
153 * @param key the key to get a hash code for
154 * @return the hash code
155 */
156 protected int hash(Object key) {
157 return System.identityHashCode(key);
158 }
159
160 /**
161 * Gets the hash code for a MapEntry.
162 * <p>
163 * This implementation uses the identity hash code.
164 *
165 * @param key the key to get a hash code for, may be null
166 * @param value the value to get a hash code for, may be null
167 * @return the hash code, as per the MapEntry specification
168 */
169 protected int hashEntry(Object key, Object value) {
170 return System.identityHashCode(key) ^
171 System.identityHashCode(value);
172 }
173
174 /**
175 * Compares two keys for equals.
176 * <p>
177 * This implementation converts the key from the entry to a real reference
178 * before comparison and uses <code>==</code>.
179 *
180 * @param key1 the first key to compare passed in from outside
181 * @param key2 the second key extracted from the entry via <code>entry.key</code>
182 * @return true if equal by identity
183 */
184 protected boolean isEqualKey(Object key1, Object key2) {
185 key2 = (keyType > HARD ? ((Reference) key2).get() : key2);
186 return (key1 == key2);
187 }
188
189 /**
190 * Compares two values for equals.
191 * <p>
192 * This implementation uses <code>==</code>.
193 *
194 * @param value1 the first value to compare passed in from outside
195 * @param value2 the second value extracted from the entry via <code>getValue()</code>
196 * @return true if equal by identity
197 */
198 protected boolean isEqualValue(Object value1, Object value2) {
199 return (value1 == value2);
200 }
201
202 //-----------------------------------------------------------------------
203 /**
204 * Write the map out using a custom routine.
205 */
206 private void writeObject(ObjectOutputStream out) throws IOException {
207 out.defaultWriteObject();
208 doWriteObject(out);
209 }
210
211 /**
212 * Read the map in using a custom routine.
213 */
214 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
215 in.defaultReadObject();
216 doReadObject(in);
217 }
218
219 }