1. /*
  2. * Copyright 2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.apache.commons.collections.map;
  17. import java.io.IOException;
  18. import java.io.ObjectInputStream;
  19. import java.io.ObjectOutputStream;
  20. import java.io.Serializable;
  21. import java.lang.ref.Reference;
  22. /**
  23. * A <code>Map</code> implementation that allows mappings to be
  24. * removed by the garbage collector and matches keys and values based
  25. * on <code>==</code> not <code>equals()</code>.
  26. * <p>
  27. * <p>
  28. * When you construct a <code>ReferenceIdentityMap</code>, you can specify what kind
  29. * of references are used to store the map's keys and values.
  30. * If non-hard references are used, then the garbage collector can remove
  31. * mappings if a key or value becomes unreachable, or if the JVM's memory is
  32. * running low. For information on how the different reference types behave,
  33. * see {@link Reference}.
  34. * <p>
  35. * Different types of references can be specified for keys and values.
  36. * The default constructor uses hard keys and soft values, providing a
  37. * memory-sensitive cache.
  38. * <p>
  39. * This map is similar to
  40. * {@link org.apache.commons.collections.map.ReferenceMap ReferenceMap}.
  41. * It differs in that keys and values in this class are compared using <code>==</code>.
  42. * <p>
  43. * This map will violate the detail of various Map and map view contracts.
  44. * As a general rule, don't compare this map to other maps.
  45. * <p>
  46. * This {@link Map} implementation does <i>not</i> allow null elements.
  47. * Attempting to add a null key or value to the map will raise a <code>NullPointerException</code>.
  48. * <p>
  49. * This implementation is not synchronized.
  50. * You can use {@link java.util.Collections#synchronizedMap} to
  51. * provide synchronized access to a <code>ReferenceIdentityMap</code>.
  52. * Remember that synchronization will not stop the garbage collecter removing entries.
  53. * <p>
  54. * All the available iterators can be reset back to the start by casting to
  55. * <code>ResettableIterator</code> and calling <code>reset()</code>.
  56. *
  57. * @see java.lang.ref.Reference
  58. *
  59. * @since Commons Collections 3.0 (previously in main package v2.1)
  60. * @version $Revision: 1.1 $ $Date: 2004/04/27 21:37:32 $
  61. *
  62. * @author Stephen Colebourne
  63. */
  64. public class ReferenceIdentityMap extends AbstractReferenceMap implements Serializable {
  65. /** Serialization version */
  66. private static final long serialVersionUID = -1266190134568365852L;
  67. /**
  68. * Constructs a new <code>ReferenceIdentityMap</code> that will
  69. * use hard references to keys and soft references to values.
  70. */
  71. public ReferenceIdentityMap() {
  72. super(HARD, SOFT, DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, false);
  73. }
  74. /**
  75. * Constructs a new <code>ReferenceIdentityMap</code> that will
  76. * use the specified types of references.
  77. *
  78. * @param keyType the type of reference to use for keys;
  79. * must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
  80. * @param valueType the type of reference to use for values;
  81. * must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
  82. */
  83. public ReferenceIdentityMap(int keyType, int valueType) {
  84. super(keyType, valueType, DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, false);
  85. }
  86. /**
  87. * Constructs a new <code>ReferenceIdentityMap</code> that will
  88. * use the specified types of references.
  89. *
  90. * @param keyType the type of reference to use for keys;
  91. * must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
  92. * @param valueType the type of reference to use for values;
  93. * must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
  94. * @param purgeValues should the value be automatically purged when the
  95. * key is garbage collected
  96. */
  97. public ReferenceIdentityMap(int keyType, int valueType, boolean purgeValues) {
  98. super(keyType, valueType, DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, purgeValues);
  99. }
  100. /**
  101. * Constructs a new <code>ReferenceIdentityMap</code> with the
  102. * specified reference types, load factor and initial capacity.
  103. *
  104. * @param keyType the type of reference to use for keys;
  105. * must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
  106. * @param valueType the type of reference to use for values;
  107. * must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
  108. * @param capacity the initial capacity for the map
  109. * @param loadFactor the load factor for the map
  110. */
  111. public ReferenceIdentityMap(int keyType, int valueType, int capacity, float loadFactor) {
  112. super(keyType, valueType, capacity, loadFactor, false);
  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. * @param purgeValues should the value be automatically purged when the
  125. * key is garbage collected
  126. */
  127. public ReferenceIdentityMap(int keyType, int valueType, int capacity,
  128. float loadFactor, boolean purgeValues) {
  129. super(keyType, valueType, capacity, loadFactor, purgeValues);
  130. }
  131. //-----------------------------------------------------------------------
  132. /**
  133. * Gets the hash code for the key specified.
  134. * <p>
  135. * This implementation uses the identity hash code.
  136. *
  137. * @param key the key to get a hash code for
  138. * @return the hash code
  139. */
  140. protected int hash(Object key) {
  141. return System.identityHashCode(key);
  142. }
  143. /**
  144. * Gets the hash code for a MapEntry.
  145. * <p>
  146. * This implementation uses the identity hash code.
  147. *
  148. * @param key the key to get a hash code for, may be null
  149. * @param value the value to get a hash code for, may be null
  150. * @return the hash code, as per the MapEntry specification
  151. */
  152. protected int hashEntry(Object key, Object value) {
  153. return System.identityHashCode(key) ^
  154. System.identityHashCode(value);
  155. }
  156. /**
  157. * Compares two keys for equals.
  158. * <p>
  159. * This implementation converts the key from the entry to a real reference
  160. * before comparison and uses <code>==</code>.
  161. *
  162. * @param key1 the first key to compare passed in from outside
  163. * @param key2 the second key extracted from the entry via <code>entry.key</code>
  164. * @return true if equal by identity
  165. */
  166. protected boolean isEqualKey(Object key1, Object key2) {
  167. key2 = (keyType > HARD ? ((Reference) key2).get() : key2);
  168. return (key1 == key2);
  169. }
  170. /**
  171. * Compares two values for equals.
  172. * <p>
  173. * This implementation uses <code>==</code>.
  174. *
  175. * @param value1 the first value to compare passed in from outside
  176. * @param value2 the second value extracted from the entry via <code>getValue()</code>
  177. * @return true if equal by identity
  178. */
  179. protected boolean isEqualValue(Object value1, Object value2) {
  180. return (value1 == value2);
  181. }
  182. //-----------------------------------------------------------------------
  183. /**
  184. * Write the map out using a custom routine.
  185. */
  186. private void writeObject(ObjectOutputStream out) throws IOException {
  187. out.defaultWriteObject();
  188. doWriteObject(out);
  189. }
  190. /**
  191. * Read the map in using a custom routine.
  192. */
  193. private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
  194. in.defaultReadObject();
  195. doReadObject(in);
  196. }
  197. }