ReferenceIdentityMap.java

  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.collections4.map;

  18. import java.io.IOException;
  19. import java.io.ObjectInputStream;
  20. import java.io.ObjectOutputStream;
  21. import java.io.Serializable;
  22. import java.lang.ref.Reference;

  23. /**
  24.  * A {@code Map} implementation that allows mappings to be
  25.  * removed by the garbage collector and matches keys and values based
  26.  * on {@code ==} not {@code equals()}.
  27.  * <p>
  28.  * When you construct a {@code ReferenceIdentityMap}, 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.  * <p>
  36.  * Different types of references can be specified for keys and values.
  37.  * The default constructor uses hard keys and soft values, providing a
  38.  * memory-sensitive cache.
  39.  * </p>
  40.  * <p>
  41.  * This map is similar to
  42.  * {@link org.apache.commons.collections4.map.ReferenceMap ReferenceMap}.
  43.  * It differs in that keys and values in this class are compared using {@code ==}.
  44.  * </p>
  45.  * <p>
  46.  * This map will violate the detail of various Map and map view contracts.
  47.  * As a general rule, don't compare this map to other maps.
  48.  * </p>
  49.  * <p>
  50.  * This {@link java.util.Map Map} implementation does <em>not</em> allow null elements.
  51.  * Attempting to add a null key or value to the map will raise a {@code NullPointerException}.
  52.  * </p>
  53.  * <p>
  54.  * This implementation is not synchronized.
  55.  * You can use {@link java.util.Collections#synchronizedMap} to
  56.  * provide synchronized access to a {@code ReferenceIdentityMap}.
  57.  * Remember that synchronization will not stop the garbage collector removing entries.
  58.  * </p>
  59.  * <p>
  60.  * All the available iterators can be reset back to the start by casting to
  61.  * {@code ResettableIterator} and calling {@code reset()}.
  62.  * </p>
  63.  * <p>
  64.  * <strong>Note that ReferenceIdentityMap is not synchronized and is not thread-safe.</strong>
  65.  * If you wish to use this map from multiple threads concurrently, you must use
  66.  * appropriate synchronization. The simplest approach is to wrap this map
  67.  * using {@link java.util.Collections#synchronizedMap}. This class may throw
  68.  * exceptions when accessed by concurrent threads without synchronization.
  69.  * </p>
  70.  *
  71.  * @param <K> the type of the keys in this map
  72.  * @param <V> the type of the values in this map
  73.  * @see java.lang.ref.Reference
  74.  * @since 3.0 (previously in main package v2.1)
  75.  */
  76. public class ReferenceIdentityMap<K, V> extends AbstractReferenceMap<K, V> implements Serializable {

  77.     /** Serialization version */
  78.     private static final long serialVersionUID = -1266190134568365852L;

  79.     /**
  80.      * Constructs a new {@code ReferenceIdentityMap} that will
  81.      * use hard references to keys and soft references to values.
  82.      */
  83.     public ReferenceIdentityMap() {
  84.         super(ReferenceStrength.HARD, ReferenceStrength.SOFT, DEFAULT_CAPACITY,
  85.                 DEFAULT_LOAD_FACTOR, false);
  86.     }

  87.     /**
  88.      * Constructs a new {@code ReferenceIdentityMap} that will
  89.      * use the specified types of references.
  90.      *
  91.      * @param keyType  the type of reference to use for keys;
  92.      *   must be {@link AbstractReferenceMap.ReferenceStrength#HARD HARD},
  93.      *   {@link AbstractReferenceMap.ReferenceStrength#SOFT SOFT},
  94.      *   {@link AbstractReferenceMap.ReferenceStrength#WEAK WEAK}
  95.      * @param valueType  the type of reference to use for values;
  96.      *   must be {@link AbstractReferenceMap.ReferenceStrength#HARD HARD},
  97.      *   {@link AbstractReferenceMap.ReferenceStrength#SOFT SOFT},
  98.      *   {@link AbstractReferenceMap.ReferenceStrength#WEAK WEAK}
  99.      */
  100.     public ReferenceIdentityMap(final ReferenceStrength keyType, final ReferenceStrength valueType) {
  101.         super(keyType, valueType, DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, false);
  102.     }

  103.     /**
  104.      * Constructs a new {@code ReferenceIdentityMap} that will
  105.      * use the specified types of references.
  106.      *
  107.      * @param keyType  the type of reference to use for keys;
  108.      *   must be {@link AbstractReferenceMap.ReferenceStrength#HARD HARD},
  109.      *   {@link AbstractReferenceMap.ReferenceStrength#SOFT SOFT},
  110.      *   {@link AbstractReferenceMap.ReferenceStrength#WEAK WEAK}
  111.      * @param valueType  the type of reference to use for values;
  112.      *   must be {@link AbstractReferenceMap.ReferenceStrength#HARD HARD},
  113.      *   {@link AbstractReferenceMap.ReferenceStrength#SOFT SOFT},
  114.      *   {@link AbstractReferenceMap.ReferenceStrength#WEAK WEAK}
  115.      * @param purgeValues should the value be automatically purged when the
  116.      *   key is garbage collected
  117.      */
  118.     public ReferenceIdentityMap(final ReferenceStrength keyType, final ReferenceStrength valueType,
  119.             final boolean purgeValues) {
  120.         super(keyType, valueType, DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, purgeValues);
  121.     }

  122.     /**
  123.      * Constructs a new {@code ReferenceIdentityMap} with the
  124.      * specified reference types, load factor and initial capacity.
  125.      *
  126.      * @param keyType  the type of reference to use for keys;
  127.      *   must be {@link AbstractReferenceMap.ReferenceStrength#HARD HARD},
  128.      *   {@link AbstractReferenceMap.ReferenceStrength#SOFT SOFT},
  129.      *   {@link AbstractReferenceMap.ReferenceStrength#WEAK WEAK}
  130.      * @param valueType  the type of reference to use for values;
  131.      *   must be {@link AbstractReferenceMap.ReferenceStrength#HARD HARD},
  132.      *   {@link AbstractReferenceMap.ReferenceStrength#SOFT SOFT},
  133.      *   {@link AbstractReferenceMap.ReferenceStrength#WEAK WEAK}
  134.      * @param capacity  the initial capacity for the map
  135.      * @param loadFactor  the load factor for the map
  136.      */
  137.     public ReferenceIdentityMap(final ReferenceStrength keyType, final ReferenceStrength valueType,
  138.             final int capacity, final float loadFactor) {
  139.         super(keyType, valueType, capacity, loadFactor, false);
  140.     }

  141.     /**
  142.      * Constructs a new {@code ReferenceIdentityMap} with the
  143.      * specified reference types, load factor and initial capacity.
  144.      *
  145.      * @param keyType  the type of reference to use for keys;
  146.      *   must be {@link AbstractReferenceMap.ReferenceStrength#HARD HARD},
  147.      *   {@link AbstractReferenceMap.ReferenceStrength#SOFT SOFT},
  148.      *   {@link AbstractReferenceMap.ReferenceStrength#WEAK WEAK}
  149.      * @param valueType  the type of reference to use for values;
  150.      *   must be {@link AbstractReferenceMap.ReferenceStrength#HARD HARD},
  151.      *   {@link AbstractReferenceMap.ReferenceStrength#SOFT SOFT},
  152.      *   {@link AbstractReferenceMap.ReferenceStrength#WEAK WEAK}
  153.      * @param capacity  the initial capacity for the map
  154.      * @param loadFactor  the load factor for the map
  155.      * @param purgeValues  should the value be automatically purged when the
  156.      *   key is garbage collected
  157.      */
  158.     public ReferenceIdentityMap(final ReferenceStrength keyType, final ReferenceStrength valueType,
  159.             final int capacity, final float loadFactor, final boolean purgeValues) {
  160.         super(keyType, valueType, capacity, loadFactor, purgeValues);
  161.     }

  162.     /**
  163.      * Gets the hash code for the key specified.
  164.      * <p>
  165.      * This implementation uses the identity hash code.
  166.      * </p>
  167.      *
  168.      * @param key  the key to get a hash code for
  169.      * @return the hash code
  170.      */
  171.     @Override
  172.     protected int hash(final Object key) {
  173.         return System.identityHashCode(key);
  174.     }

  175.     /**
  176.      * Gets the hash code for a MapEntry.
  177.      * <p>
  178.      * This implementation uses the identity hash code.
  179.      * </p>
  180.      *
  181.      * @param key  the key to get a hash code for, may be null
  182.      * @param value  the value to get a hash code for, may be null
  183.      * @return the hash code, as per the MapEntry specification
  184.      */
  185.     @Override
  186.     protected int hashEntry(final Object key, final Object value) {
  187.         return System.identityHashCode(key) ^
  188.                System.identityHashCode(value);
  189.     }

  190.     /**
  191.      * Compares two keys for equals.
  192.      * <p>
  193.      * This implementation converts the key from the entry to a real reference
  194.      * before comparison and uses {@code ==}.
  195.      * </p>
  196.      *
  197.      * @param key1  the first key to compare passed in from outside
  198.      * @param key2  the second key extracted from the entry via {@code entry.key}
  199.      * @return true if equal by identity
  200.      */
  201.     @Override
  202.     protected boolean isEqualKey(final Object key1, Object key2) {
  203.         key2 = isKeyType(ReferenceStrength.HARD) ? key2 : ((Reference<?>) key2).get();
  204.         return key1 == key2;
  205.     }

  206.     /**
  207.      * Compares two values for equals.
  208.      * <p>
  209.      * This implementation uses {@code ==}.
  210.      * </p>
  211.      *
  212.      * @param value1  the first value to compare passed in from outside
  213.      * @param value2  the second value extracted from the entry via {@code getValue()}
  214.      * @return true if equal by identity
  215.      */
  216.     @Override
  217.     protected boolean isEqualValue(final Object value1, final Object value2) {
  218.         return value1 == value2;
  219.     }

  220.     /**
  221.      * Deserializes the map in using a custom routine.
  222.      *
  223.      * @param in the input stream
  224.      * @throws IOException if an error occurs while reading from the stream
  225.      * @throws ClassNotFoundException if an object read from the stream cannot be loaded
  226.      */
  227.     private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
  228.         in.defaultReadObject();
  229.         doReadObject(in);
  230.     }

  231.     /**
  232.      * Serializes this object to an ObjectOutputStream.
  233.      *
  234.      * @param out the target ObjectOutputStream.
  235.      * @throws IOException thrown when an I/O errors occur writing to the target stream.
  236.      */
  237.     private void writeObject(final ObjectOutputStream out) throws IOException {
  238.         out.defaultWriteObject();
  239.         doWriteObject(out);
  240.     }

  241. }