java8 hash算法

Posted 茅坤宝骏氹

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java8 hash算法相关的知识,希望对你有一定的参考价值。

一、hash算法

  哈希算法将任意长度的二进制值映射为较短的固定长度的二进制值,这个小的二进制值称为哈希值。哈希值是一段数据唯一且极其紧凑的数值表示形式。如果散列一段明文而且哪怕只更改该段落的一个字母,随后的哈希都将产生不同的值。要找到散列为同一个值的两个不同的输入,在计算上是不可能的,所以数据的哈希值可以检验数据的完整性。一般用于快速查找和加密算法。

 

二、jdk的hash算法实现

(1)Interger

    private final int value;

    @Override
    public int hashCode() {
        return Integer.hashCode(value);
    }

    public static int hashCode(int value) {
        return value;
    }

Integer的hash算法就是直接获取它的数值。int整数范围很大,分散广冲突小。

 

(2)Short

    private final short value;

    @Override
    public int hashCode() {
        return Short.hashCode(value);
    }

    public static int hashCode(short value) {
        return (int)value;
    }

 

(3)Byte

    private final byte value;

    @Override
    public int hashCode() {
        return Byte.hashCode(value);
    }

    public static int hashCode(byte value) {
        return (int)value;
    }

 

(4)Long

    private final long value;

    @Override
    public 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;

    @Override
    public 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;

    @Override
    public 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;

    @Override
    public int hashCode() {
        return Boolean.hashCode(value);
    }

    public static int hashCode(boolean value) {
        return value ? 1231 : 1237;
    }

 

(8)Character

    private final char value;

    @Override
    public 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;
    }

 

(10)Object

    public native int hashCode();

 

(11)自定义对象

public class Node<T> {

    private T data;
    private Node<T> next = null;
    
    @Override
    public 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 null
        if (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 progress
        Entry<?,?>[] tab = table;
        for (Entry<?,?> entry : tab) {
            while (entry != null) {
                h += entry.hashCode();
                entry = entry.next;
            }
        }

        loadFactor = -loadFactor;  // Mark hashCode computation complete

        return h;
    }

 

以上是关于java8 hash算法的主要内容,如果未能解决你的问题,请参考以下文章

读源码 HashMap Java8

一致性哈希算法PHP测试片段

Java8 HashMap ,hashTable,TreeMap 看源代码看到的一些特性

HashMap源码阅读笔记——HashMap的实现原理浅析

如何从URL获取片段标识符(hash#之后的值)?

阿里天猫3面(Java研发面试题):GC回收+Redis Hash算法+架构部署+秒杀等