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); |
160 |
< |
return h; |
149 |
> |
* Applies a supplemental hash function to a given hashCode, which |
150 |
> |
* defends against poor quality hash functions. This is critical |
151 |
> |
* because HashMap uses power-of two length hash tables, that |
152 |
> |
* otherwise encounter collisions for hashCodes that do not differ |
153 |
> |
* in lower bits. |
154 |
> |
*/ |
155 |
> |
static int hash(int h) { |
156 |
> |
// This function ensures that hashCodes that differ only by |
157 |
> |
// constant multiples at each bit position have a bounded |
158 |
> |
// number of collisions (approximately 8 at default load factor). |
159 |
> |
h ^= (h >>> 20) ^ (h >>> 12); |
160 |
> |
return h ^ (h >>> 7) ^ (h >>> 4); |
161 |
|
} |
162 |
|
|
163 |
|
/** |
761 |
|
* @throws NullPointerException if the specified key is null |
762 |
|
*/ |
763 |
|
public V get(Object key) { |
764 |
< |
int hash = hash(key); // throws NullPointerException if key null |
764 |
> |
int hash = hash(key.hashCode()); |
765 |
|
return segmentFor(hash).get(key, hash); |
766 |
|
} |
767 |
|
|
775 |
|
* @throws NullPointerException if the specified key is null |
776 |
|
*/ |
777 |
|
public boolean containsKey(Object key) { |
778 |
< |
int hash = hash(key); // throws NullPointerException if key null |
778 |
> |
int hash = hash(key.hashCode()); |
779 |
|
return segmentFor(hash).containsKey(key, hash); |
780 |
|
} |
781 |
|
|
875 |
|
public V put(K key, V value) { |
876 |
|
if (value == null) |
877 |
|
throw new NullPointerException(); |
878 |
< |
int hash = hash(key); |
878 |
> |
int hash = hash(key.hashCode()); |
879 |
|
return segmentFor(hash).put(key, hash, value, false); |
880 |
|
} |
881 |
|
|
889 |
|
public V putIfAbsent(K key, V value) { |
890 |
|
if (value == null) |
891 |
|
throw new NullPointerException(); |
892 |
< |
int hash = hash(key); |
892 |
> |
int hash = hash(key.hashCode()); |
893 |
|
return segmentFor(hash).put(key, hash, value, true); |
894 |
|
} |
895 |
|
|
915 |
|
* @throws NullPointerException if the specified key is null |
916 |
|
*/ |
917 |
|
public V remove(Object key) { |
918 |
< |
int hash = hash(key); |
918 |
> |
int hash = hash(key.hashCode()); |
919 |
|
return segmentFor(hash).remove(key, hash, null); |
920 |
|
} |
921 |
|
|
925 |
|
* @throws NullPointerException if the specified key is null |
926 |
|
*/ |
927 |
|
public boolean remove(Object key, Object value) { |
928 |
< |
int hash = hash(key); // throws NullPointerException if key null |
928 |
> |
int hash = hash(key.hashCode()); |
929 |
|
if (value == null) |
930 |
|
return false; |
931 |
|
return segmentFor(hash).remove(key, hash, value) != null; |
939 |
|
public boolean replace(K key, V oldValue, V newValue) { |
940 |
|
if (oldValue == null || newValue == null) |
941 |
|
throw new NullPointerException(); |
942 |
< |
int hash = hash(key); |
942 |
> |
int hash = hash(key.hashCode()); |
943 |
|
return segmentFor(hash).replace(key, hash, oldValue, newValue); |
944 |
|
} |
945 |
|
|
953 |
|
public V replace(K key, V value) { |
954 |
|
if (value == null) |
955 |
|
throw new NullPointerException(); |
956 |
< |
int hash = hash(key); |
956 |
> |
int hash = hash(key.hashCode()); |
957 |
|
return segmentFor(hash).replace(key, hash, value); |
958 |
|
} |
959 |
|
|