在進行數據交換時,如果主鍵不是整型,需要對字符串,或聯合主鍵拼接為字符串,進行hash,再進行取模分片,使用的是String自帶的hashCode()方法,本來是件很方便的事,但是有些字符串取hashCode竟然是負數,使得分片為負數,找不到對應的分片,我們先看一下String 生成hashCode的代碼:
/** * Returns a hash code for this string. The hash code for a * {@code String} object is computed as * <blockquote><pre> * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1] * </pre></blockquote> * using {@code int} arithmetic, where {@code s[i]} is the * <i>i</i>th character of the string, {@code n} is the length of * the string, and {@code ^} indicates exponentiation. * (The hash value of the empty string is zero.) * * @return a hash code value for this object. */ public int hashCode() { int h = hash; if (h == 0 && value.length > 0) { char val[] = value; for (int i = 0; i < value.length; i++) { h = 31 * h + val[i]; } hash = h; } return h; }
主要是根據字符串中字符的ascii碼值來計算的,即 31 * hash + 字符的ASCII碼值,int型的值取值范圍為Integer.MIN_VALUE(-2147483648)~Integer.MAX_VALUE(2147483647),所以如果字符串比較長,計算的數值就可能超出Integer.MAX_VALUE,造成數值溢出,值變成負數
幾種比較極端的字符串hashCode值:
String hashStr0 = "35953305172933/"; System.out.println(hashStr0.hashCode()); // 2147483647 Integer.MAX_VALUE System.out.println(Math.abs(hashStr0.hashCode())); // 2147483647 Integer.MAX_VALUE System.out.println("-------------------"); String hashStr = "359533051729330"; System.out.println(hashStr.hashCode()); // -2147483648 Integer.MIN_VALUE System.out.println(Math.abs(hashStr.hashCode())); // -2147483648 Integer.MIN_VALUE System.out.println("-------------------"); String hashStr2 = "56800004874"; System.out.println(hashStr2.hashCode()); // -2082984168 System.out.println(Math.abs(hashStr2.hashCode())); // 2082984168 System.out.println("-------------------"); String hashStr3 = ""; System.out.println(hashStr3.hashCode()); // 0 System.out.println(Math.abs(hashStr3.hashCode())); // 0 System.out.println("-------------------");
對於字符串“359533051729330”的hashCode為Integer.MIN_VALUE,我們使用取絕對值還是超出Integer.MAX_VALUE,還是Integer.MIN_VALUE,所以針對這種極端情況是不可用的
要想利用hashCode為非負數,可以Integer.MAX_VALUE和與操作,這樣最大正整數的符號位為0,與任何數與操作都是0,即是正數
int hash = str.hashCode() & Integer.MAX_VALUE;
2147483647 Integer.MAX_VALUE