哈希算法将任意长度的二进制值映射为较短的固定长度的二进制值,这个小的二进制值称为哈希值。哈希值是一段数据唯一且极其紧凑的数值表示形式。如果散列一段明文而且哪怕只更改该段落的一个字母,随后的哈希都将产生不同的值。要找到散列为同一个值的两个不同的输入,在计算上是不可能的,所以数据的哈希值可以检验数据的完整性。一般用于快速查找和加密算法。
二、对象hash总结
Integer、Byte、Short、Character都是转换为int类型作为hashcode
Boolean true值hashcode为1231,false值hashcode为1237
Long 取高32位和低32位与值转成int类型作为hashcode
Double 将64bit值转成long类型,然后按照Long类型进行获取hashcode
Float 将32bit值转成int类型,检查int值是否来自NAN值转换的,若是hashcode为0x7fc00000,否则为该转换值。
String 将字符串里面的字符以31进制求和,既hash=hash*31+value[i]
Object 以内存首字节的地址进行计算hash值
HashMap 将所有Entry的hashcode相加组成HashMap的hashcode
Hashtable EntrySet长度0或者加载因子小于0时,hashcode为0,否则将所有key的hashcode相加组成HashMap的hashcode
三、jdk的hash算法实现
(1)Interger
private final int value; @Overridepublic int hashCode() {return Integer.hashCode(value);} public static int hashCode(int value) {return value;}
Integer的hash算法就是直接获取它的数值。int整数范围很大,分散广冲突小。
(2)Short
private final short value;@Overridepublic int hashCode() {return Short.hashCode(value);}public static int hashCode(short value) {return (int)value;}
(3)Byte
private final byte value;@Overridepublic int hashCode() {return Byte.hashCode(value);}public static int hashCode(byte value) {return (int)value;}
(4)Long
private final long value;@Overridepublic int hashCode() {return Long.hashCode(value);}public static int hashCode(long value) {return (int)(value ^ (value >>> 32));}
long类型作为索引范围太大,需要转为int类型。这里简单的获取低32位容易导致散列不均,因为高位部分没有被利用。所以这里采用逻辑右移32位,让高32位和低32位进行XOR操作,导致高位低位都能被利用到
(5)Double
private final double value;@Overridepublic int hashCode() {return Double.hashCode(value);}public static int hashCode(double value) {long bits = doubleToLongBits(value);return (int)(bits ^ (bits >>> 32));}
由于double不能当成索引,所以需要转换成整数
由于double数据类型底层采用64位bit码表示,采用IEEE浮点标准编码。如果将它使用8字节整数编码方式,就能获取一个long类型的数字
long类型作为索引范围太大,需要转为int类型。这里简单的获取低32位容易导致散列不均,因为高位部分没有被利用。所以这里采用逻辑右移32位,让高32位和低32位进行XOR操作,导致高位低位都能被利用到
最后得到的数字强转int,只保留已经被充分打乱的低32位
(6)Float
private final float value;@Overridepublic int hashCode() {return Float.hashCode(value);}public static int hashCode(float value) {return floatToIntBits(value);}public static int floatToIntBits(float value) {int result = floatToRawIntBits(value);// Check for NaN based on values of bit fields, maximum// exponent and nonzero significand.if ( ((result & FloatConsts.EXP_BIT_MASK) ==FloatConsts.EXP_BIT_MASK) &&(result & FloatConsts.SIGNIF_BIT_MASK) != 0)result = 0x7fc00000;return result;}public static native int floatToRawIntBits(float value);
public class FloatConsts {public static final int EXP_BIT_MASK = 2139095040;public static final int SIGNIF_BIT_MASK = 8388607;//... }
(7)Boolean
private final boolean value;@Overridepublic int hashCode() {return Boolean.hashCode(value);}public static int hashCode(boolean value) {return value ? 1231 : 1237;}
采用两个质数作为true或false的索引。这两个质数足够大,用来作为索引时,出现碰撞的可能性低。
(8)Character
private final char value;@Overridepublic int hashCode() {return Character.hashCode(value);}public static int hashCode(char value) {return (int)value;}
(9)String
private final char value[];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;}
采用质数31作为基数,逐位加权,打乱整个字符的权重和排列位置,使得散列效果更好。
(10)Object
public native int hashCode();
(11)自定义对象
public class Node<T> {private T data;private Node<T> next = null;@Overridepublic int hashCode() {int hash = 3;hash = 97 * hash + Objects.hashCode(this.data);hash = 97 * hash + Objects.hashCode(this.next);return hash;} }
public final class Objects {public static int hashCode(Object o) {return o != null ? o.hashCode() : 0;}//... }
(12)HashMap
static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}public int hashCode() {int h = 0;Iterator<Entry<K,V>> i = entrySet().iterator();while (i.hasNext())h += i.next().hashCode();return h;}
(13)Hashtable
public synchronized V put(K key, V value) {// Make sure the value is not nullif (value == null) {throw new NullPointerException();}// Makes sure the key is not already in the hashtable.Entry<?,?> tab[] = table;int hash = key.hashCode();int index = (hash & 0x7FFFFFFF) % tab.length;@SuppressWarnings("unchecked")Entry<K,V> entry = (Entry<K,V>)tab[index];for(; entry != null ; entry = entry.next) {if ((entry.hash == hash) && entry.key.equals(key)) {V old = entry.value;entry.value = value;return old;}}addEntry(hash, key, value, index);return null;}public synchronized int hashCode() {int h = 0;if (count == 0 || loadFactor < 0)return h; // Returns zero loadFactor = -loadFactor; // Mark hashCode computation in progressEntry<?,?>[] tab = table;for (Entry<?,?> entry : tab) {while (entry != null) {h += entry.hashCode();entry = entry.next;}}loadFactor = -loadFactor; // Mark hashCode computation completereturn h;}