接触编程这么久了,一直会遇到某些高频词,例如,哈希。hashtable,hashmap,hashset等等等。都有hash一次。那什么是哈希值呢?百度本科解释是,Hash,一般翻译做“散列”,也有直接音译为“哈希”的,就是把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值。
那是怎么把输入转换成固定长度的散列值呢?我也很好奇。
所以特地找了一下string的hashcode源码。
hashcode()源码
public int hashCode() {
int h = hash;
int len = count;
if (h == 0 && len > 0) {
int off = offset;
char val[] = value;
for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}
我们通过看源码得知,它里面有个for循环,遍历字符串,每一位的ASCII值都会乘于31的n次幂,这个n的话对于len-index.
例如:我们求abcde的hash code。
输入abcd
// 第一步 = (int)'a'
// 第二步 = (31 * (int)'a') + (int)'b'
// 第三步 = 31 * ((31 * (int)'a') + (int)'b') + (int)'c
// 第四步 = 31 * (31 * ((31 * (int)'a') + (int)'b') + (int)'c') + (int)'d'
// 第五步 = 31 * (31 * (31 * ((31 * (int)'a') + (int)'b') + (int)'c') + (int)'d') + (int)'e'
也就abcd的hashcode值为,a*31^4+b*31^3+c*31^2+d*31^1+e*31^0
也就是对每一位的num*31^n,n=len-index进行累加
很多书上都说hashcode值不可逆,通过源码查看,确实不可逆。
为什么是31呢?
看一下解释:
之所以选择值31是因为它是奇数素数。如果它是偶数,并且乘法溢出,则信息将丢失,因为2的乘法相当于移位。使用素数的优点不太清楚,但它是传统的。31的一个很好的特性是,可以用一个移位和一个减法来代替乘法,以获得更好的性能:31×i =(i < 5)- i。现代VMS自动完成这种优化。