62 |
|
* does <em>not</em> allow <tt>null</tt> to be used as a key or value. |
63 |
|
* |
64 |
|
* <p>This class is a member of the |
65 |
< |
* <a href="{@docRoot}/../guide/collections/index.html"> |
65 |
> |
* <a href="{@docRoot}/../technotes/guides/collections/index.html"> |
66 |
|
* Java Collections Framework</a>. |
67 |
|
* |
68 |
|
* @since 1.5 |
146 |
|
/* ---------------- Small Utilities -------------- */ |
147 |
|
|
148 |
|
/** |
149 |
< |
* Returns a hash code for non-null Object x. |
150 |
< |
* Uses the same hash code spreader as most other java.util hash tables. |
151 |
< |
* @param x the object serving as a key |
152 |
< |
* @return the hash code |
153 |
< |
*/ |
154 |
< |
static int hash(Object x) { |
155 |
< |
int h = x.hashCode(); |
156 |
< |
h += ~(h << 9); |
157 |
< |
h ^= (h >>> 14); |
158 |
< |
h += (h << 4); |
159 |
< |
h ^= (h >>> 10); |
149 |
> |
* Applies a supplemental hash function to a given hashCode, which |
150 |
> |
* defends against poor quality hash functions. This is critical |
151 |
> |
* because ConcurrentHashMap uses power-of-two length hash tables, |
152 |
> |
* that otherwise encounter collisions for hashCodes that do not |
153 |
> |
* differ in lower bits. |
154 |
> |
*/ |
155 |
> |
private static int hash(int h) { |
156 |
> |
// Spread bits to regularize both segment and index locations, |
157 |
> |
// using variant of Jenkins's shift-based hash. |
158 |
> |
h += ~(h << 13); |
159 |
> |
h ^= h >>> 7; |
160 |
> |
h += h << 3; |
161 |
> |
h ^= h >>> 17; |
162 |
> |
h += h << 5; |
163 |
|
return h; |
164 |
|
} |
165 |
|
|
764 |
|
* @throws NullPointerException if the specified key is null |
765 |
|
*/ |
766 |
|
public V get(Object key) { |
767 |
< |
int hash = hash(key); // throws NullPointerException if key null |
767 |
> |
int hash = hash(key.hashCode()); |
768 |
|
return segmentFor(hash).get(key, hash); |
769 |
|
} |
770 |
|
|
778 |
|
* @throws NullPointerException if the specified key is null |
779 |
|
*/ |
780 |
|
public boolean containsKey(Object key) { |
781 |
< |
int hash = hash(key); // throws NullPointerException if key null |
781 |
> |
int hash = hash(key.hashCode()); |
782 |
|
return segmentFor(hash).containsKey(key, hash); |
783 |
|
} |
784 |
|
|
878 |
|
public V put(K key, V value) { |
879 |
|
if (value == null) |
880 |
|
throw new NullPointerException(); |
881 |
< |
int hash = hash(key); |
881 |
> |
int hash = hash(key.hashCode()); |
882 |
|
return segmentFor(hash).put(key, hash, value, false); |
883 |
|
} |
884 |
|
|
892 |
|
public V putIfAbsent(K key, V value) { |
893 |
|
if (value == null) |
894 |
|
throw new NullPointerException(); |
895 |
< |
int hash = hash(key); |
895 |
> |
int hash = hash(key.hashCode()); |
896 |
|
return segmentFor(hash).put(key, hash, value, true); |
897 |
|
} |
898 |
|
|
918 |
|
* @throws NullPointerException if the specified key is null |
919 |
|
*/ |
920 |
|
public V remove(Object key) { |
921 |
< |
int hash = hash(key); |
921 |
> |
int hash = hash(key.hashCode()); |
922 |
|
return segmentFor(hash).remove(key, hash, null); |
923 |
|
} |
924 |
|
|
928 |
|
* @throws NullPointerException if the specified key is null |
929 |
|
*/ |
930 |
|
public boolean remove(Object key, Object value) { |
931 |
+ |
int hash = hash(key.hashCode()); |
932 |
|
if (value == null) |
933 |
|
return false; |
930 |
– |
int hash = hash(key); |
934 |
|
return segmentFor(hash).remove(key, hash, value) != null; |
935 |
|
} |
936 |
|
|
942 |
|
public boolean replace(K key, V oldValue, V newValue) { |
943 |
|
if (oldValue == null || newValue == null) |
944 |
|
throw new NullPointerException(); |
945 |
< |
int hash = hash(key); |
945 |
> |
int hash = hash(key.hashCode()); |
946 |
|
return segmentFor(hash).replace(key, hash, oldValue, newValue); |
947 |
|
} |
948 |
|
|
956 |
|
public V replace(K key, V value) { |
957 |
|
if (value == null) |
958 |
|
throw new NullPointerException(); |
959 |
< |
int hash = hash(key); |
959 |
> |
int hash = hash(key.hashCode()); |
960 |
|
return segmentFor(hash).replace(key, hash, value); |
961 |
|
} |
962 |
|
|