HashMap的hashSeed的问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | final boolean initHashSeedAsNeeded( int capacity) { //通过上面的过程,我们知道了currentAltHashing =false boolean currentAltHashing = hashSeed != 0 ; //useAltHashing = false boolean useAltHashing = sun.misc.VM.isBooted() && (capacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD); // false ^ false 结果为false,switching为false boolean switching = currentAltHashing ^ useAltHashing; if (switching) { hashSeed = useAltHashing ? sun.misc.Hashing.randomHashSeed( this ) : 0 ; } //返回false return switching; } |
—–本文只针对1.7版本的HashMap所讲解.
我们知道了HashMap生成hash码的时候会涉及到hashSeed的问题,
public V put(K key, V value) { if (table == EMPTY_TABLE) { inflateTable(threshold); } if (key == null) return putForNullKey(value); //对key生成hash码 int hash = hash(key); int i = indexFor(hash, table.length); for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(hash, key, value, i); return null; }
这里对key进行生成hash码,它是怎么生成的呢?我们看下面的代码:
transient int hashSeed = 0; final int hash(Object k) { int h = hashSeed; if (0 != h && k instanceof String) { return sun.misc.Hashing.stringHash32((String) k); } h ^= k.hashCode(); h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); }
我们这里一步一步来解释,首先hashSeed怎么来的?它是HashMap的属性,在HashMap初始化时已经为0,但是我们在执行inflateTable方法时执行了initHashSeedAsNeeded方法这里面对hashSeed又执行了一次赋值操作,我们来代码:
private void inflateTable(int toSize) { // Find a power of 2 >= toSize int capacity = roundUpToPowerOf2(toSize); threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1); table = new Entry[capacity]; initHashSeedAsNeeded(capacity); } //hashSeed在这个方法里面又进行了一次赋值操作,为了让读者了解的更多,我尽量做的详细一点. final boolean initHashSeedAsNeeded(int capacity) { //当我们初始化的时候hashSeed为0,0!=0 这时为false. boolean currentAltHashing = hashSeed != 0; //isBooted()这个方法里面返回了一个boolean值,我们看下面的代码 boolean useAltHashing = sun.misc.VM.isBooted() && (capacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD); boolean switching = currentAltHashing ^ useAltHashing; if (switching) { hashSeed = useAltHashing ? sun.misc.Hashing.randomHashSeed(this) : 0; } return switching; }
sun.misc.VM类的代码如下:
private static volatile boolean booted = false; public static boolean isBooted() { return booted; }
这里返回的是booted 的值,但是booted 默认为false,但是我们不知道VM启动的时候是否对它又赋了新值,怎么办呢?我们可以用一个土办法来测试如下:
我们可以看到在Map执行前booted的值为true,然而我们HashMap执行的时候并没有给它赋值,所以它为true,然后我们比较后面的条件看看,我们看见要拿初始容量比较Holder.ALTERNATIVE_HASHING_THRESHOLD,但是我们不知道这个为多少.看代码.
static final int ALTERNATIVE_HASHING_THRESHOLD_DEFAULT = Integer.MAX_VALUE;//这里为2147483647,它是HashMap的属性,初始化的时候就已赋值 //Holder这个类是HashMap的子类, private static class Holder { //这里定义了我们需要的常量,但是它没赋值,我们看看它是怎么赋值的? static final int ALTERNATIVE_HASHING_THRESHOLD; static { String altThreshold = java.security.AccessController.doPrivileged( new sun.security.action.GetPropertyAction( "jdk.map.althashing.threshold")); int threshold; try { threshold = (null != altThreshold) ? Integer.parseInt(altThreshold) : ALTERNATIVE_HASHING_THRESHOLD_DEFAULT; // disable alternative hashing if -1 if (threshold == -1) { threshold = Integer.MAX_VALUE; } if (threshold < 0) { throw new IllegalArgumentException("value must be positive integer."); } } catch(IllegalArgumentException failed) { throw new Error("Illegal value for 'jdk.map.althashing.threshold'", failed); } ALTERNATIVE_HASHING_THRESHOLD = threshold; } }
我们通过代码看到ALTERNATIVE_HASHING_THRESHOLD来自threshold,threshold哪里呢?看上面得知来自判断条件里面.那我们就来看看判断条件altThreshold,altThreshold来自一个本地方法,我们还是用老方法,看看它的值为什么.
@CallerSensitive public static native <T> T doPrivileged(PrivilegedAction<T> action);
通过上面的流程以后,我们知道hashSeed 并没有重新赋值,最终hashSeed的值为0;
分类:
java
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!