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.util.Map; 024 025 /** 026 * A <code>Map</code> implementation that matches keys and values based 027 * on <code>==</code> not <code>equals()</code>. 028 * <p> 029 * This map will violate the detail of various Map and map view contracts. 030 * As a general rule, don't compare this map to other maps. 031 * <p> 032 * <strong>Note that IdentityMap is not synchronized and is not thread-safe.</strong> 033 * If you wish to use this map from multiple threads concurrently, you must use 034 * appropriate synchronization. The simplest approach is to wrap this map 035 * using {@link java.util.Collections#synchronizedMap(Map)}. This class may throw 036 * exceptions when accessed by concurrent threads without synchronization. 037 * 038 * @since Commons Collections 3.0 039 * @version $Revision: 646777 $ $Date: 2008-04-10 13:33:15 +0100 (Thu, 10 Apr 2008) $ 040 * 041 * @author java util HashMap 042 * @author Stephen Colebourne 043 */ 044 public class IdentityMap 045 extends AbstractHashedMap implements Serializable, Cloneable { 046 047 /** Serialisation version */ 048 private static final long serialVersionUID = 2028493495224302329L; 049 050 /** 051 * Constructs a new empty map with default size and load factor. 052 */ 053 public IdentityMap() { 054 super(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_THRESHOLD); 055 } 056 057 /** 058 * Constructs a new, empty map with the specified initial capacity. 059 * 060 * @param initialCapacity the initial capacity 061 * @throws IllegalArgumentException if the initial capacity is less than one 062 */ 063 public IdentityMap(int initialCapacity) { 064 super(initialCapacity); 065 } 066 067 /** 068 * Constructs a new, empty map with the specified initial capacity and 069 * load factor. 070 * 071 * @param initialCapacity the initial capacity 072 * @param loadFactor the load factor 073 * @throws IllegalArgumentException if the initial capacity is less than one 074 * @throws IllegalArgumentException if the load factor is less than zero 075 */ 076 public IdentityMap(int initialCapacity, float loadFactor) { 077 super(initialCapacity, loadFactor); 078 } 079 080 /** 081 * Constructor copying elements from another map. 082 * 083 * @param map the map to copy 084 * @throws NullPointerException if the map is null 085 */ 086 public IdentityMap(Map map) { 087 super(map); 088 } 089 090 //----------------------------------------------------------------------- 091 /** 092 * Gets the hash code for the key specified. 093 * This implementation uses the identity hash code. 094 * 095 * @param key the key to get a hash code for 096 * @return the hash code 097 */ 098 protected int hash(Object key) { 099 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 protected boolean isEqualKey(Object key1, Object key2) { 111 return (key1 == key2); 112 } 113 114 /** 115 * Compares two values for equals. 116 * This implementation uses <code>==</code>. 117 * 118 * @param value1 the first value to compare 119 * @param value2 the second value to compare 120 * @return true if equal by identity 121 */ 122 protected boolean isEqualValue(Object value1, Object value2) { 123 return (value1 == value2); 124 } 125 126 /** 127 * Creates an entry to store the data. 128 * This implementation creates an IdentityEntry instance. 129 * 130 * @param next the next entry in sequence 131 * @param hashCode the hash code to use 132 * @param key the key to store 133 * @param value the value to store 134 * @return the newly created entry 135 */ 136 protected HashEntry createEntry(HashEntry next, int hashCode, Object key, Object value) { 137 return new IdentityEntry(next, hashCode, key, value); 138 } 139 140 //----------------------------------------------------------------------- 141 /** 142 * HashEntry 143 */ 144 protected static class IdentityEntry extends HashEntry { 145 146 protected IdentityEntry(HashEntry next, int hashCode, Object key, Object value) { 147 super(next, hashCode, key, value); 148 } 149 150 public boolean equals(Object obj) { 151 if (obj == this) { 152 return true; 153 } 154 if (obj instanceof Map.Entry == false) { 155 return false; 156 } 157 Map.Entry other = (Map.Entry) obj; 158 return 159 (getKey() == other.getKey()) && 160 (getValue() == other.getValue()); 161 } 162 163 public int hashCode() { 164 return System.identityHashCode(getKey()) ^ 165 System.identityHashCode(getValue()); 166 } 167 } 168 169 //----------------------------------------------------------------------- 170 /** 171 * Clones the map without cloning the keys or values. 172 * 173 * @return a shallow clone 174 */ 175 public Object clone() { 176 return super.clone(); 177 } 178 179 /** 180 * Write the map out using a custom routine. 181 */ 182 private void writeObject(ObjectOutputStream out) throws IOException { 183 out.defaultWriteObject(); 184 doWriteObject(out); 185 } 186 187 /** 188 * Read the map in using a custom routine. 189 */ 190 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { 191 in.defaultReadObject(); 192 doReadObject(in); 193 } 194 195 }