浅谈System.identityHashCode
程序员文章站
2022-06-07 13:06:41
...
今天在查看一下源代码的时候突然发现要调用这个函数的地方,其实如果从定义上面来看的话,感觉不是很明白,说句心里话,我的理解是这样的,它是根据对象的内存地址来生成的hashCode,比如想这么一个情景,一般来说我们都会重载hashCode函数,就那String类的hashCode来说吧,就是与字符串的内容有关系,如果我们new两个内容相同的string,那么内存地址肯定是不相同的,那么怎么才能得到原生的hashCode呢,这个函数就是干这个事情的。
今天其实我看到了一个自己写的数据结构,就是保存一个对象和它的引用计数的。 我看的源代码是hessian,在对象序列化的时候会统计对象的引用情况,比如说Parent类,它被Child引用,它也被GrandParent引用,那么在序列化Child和GrandParent的时候,就有一个数据结构来存储Student对象被引用的情况。所以我就顺便看了一下IdenttityIntMap的函数实现:
public class IdentityIntMap { private Object[] keys; private int[] values; private int prime; private int size; public IdentityIntMap(int size) { keys = new Object[size]; values = new int[size]; prime = findBiggestPrime(size); this.size = 0; } public int get(Object key){ int hash = System.identityHashCode(key) % prime; while(true){ Object testKey = keys[hash]; if(testKey == null){ return -1; } else if(testKey == key){ return values[hash]; } else { hash = (hash + 1) % prime; } } } public int put(Object key, int value, boolean replace) { int hash = System.identityHashCode(key) % prime; while (true) { Object testKey = keys[hash]; if (testKey == null) { keys[hash] = key; values[hash] = value; size++; if (keys.length <= 4 * size) { resize(4 * keys.length); } return value; } else if (testKey != key) { hash = (hash + 1) % prime; continue; } else if (replace) { int old = values[hash]; values[hash] = value; return old; } } } public int put(Object key, int value) { return put(key, value, true); } private void resize(int newSize) { int[] oldValues = values; Object[] oldKeys = keys; values = new int[newSize]; keys = new Object[newSize]; size = 0; prime = findBiggestPrime(newSize); for (int i = 0; i < oldKeys.length; i++) { if(oldKeys[i] != null){ put(oldKeys[i], oldValues[i], true); } } } public int findBiggestPrime(int value) { for (int i = PRIMES.length - 1; i >= 0; i--) { if (PRIMES[i] <= value) { return PRIMES[i]; } } return 2; } public static final int[] PRIMES = { 1, /* 1<< 0 = 1 */ 2, /* 1<< 1 = 2 */ 3, /* 1<< 2 = 4 */ 7, /* 1<< 3 = 8 */ 13, /* 1<< 4 = 16 */ 31, /* 1<< 5 = 32 */ 61, /* 1<< 6 = 64 */ 127, /* 1<< 7 = 128 */ 251, /* 1<< 8 = 256 */ 509, /* 1<< 9 = 512 */ 1021, /* 1<<10 = 1024 */ 2039, /* 1<<11 = 2048 */ 4093, /* 1<<12 = 4096 */ 8191, /* 1<<13 = 8192 */ 16381, /* 1<<14 = 16384 */ 32749, /* 1<<15 = 32768 */ 65521, /* 1<<16 = 65536 */ 131071, /* 1<<17 = 131072 */ 262139, /* 1<<18 = 262144 */ 524287, /* 1<<19 = 524288 */ 1048573, /* 1<<20 = 1048576 */ 2097143, /* 1<<21 = 2097152 */ 4194301, /* 1<<22 = 4194304 */ 8388593, /* 1<<23 = 8388608 */ 16777213, /* 1<<24 = 16777216 */ 33554393, /* 1<<25 = 33554432 */ 67108859, /* 1<<26 = 67108864 */ 134217689, /* 1<<27 = 134217728 */ 268435399, /* 1<<28 = 268435456 */ }; }
下面的是测试方法:
public class IdentityIntMapTest { public static void main(String[] args) { IdentityIntMap intMap = new IdentityIntMap(10); String aaa = "aaa"; intMap.put(aaa, 1); intMap.put(new String("bbb"), 2); intMap.put(new String("ccc"), 3); intMap.put(new String("ddd"), 4); intMap.put(new String("eee"), 5); System.out.println(intMap.get(aaa)); System.out.println(intMap.get("bbb")); } }
当时我感觉到intMap.get("bbb")找不到,当时感觉到很奇怪,如果我吧IdentityIntMap的底层实现改成key.hashCode就可以了,但是后来想了一下这个数据结构的使用用途就是这样的我不能顺便修改,把今天的发现记录在这里吧。