View Javadoc

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 }