HashMap在Android和Java中的不一样实现

原由

今天在项目中遇到一个很"奇葩"的问题。状况大体是这样的:Android终端和服务器(Spring),彻底相同的字符串键值对放入HashMap中居然顺序不同,这直接致使了服务器和Android终端用HmacSHA256算法加密出的摘要也不同,服务器也就没法进行正确的数据验证。算法

而后带着郁闷的心情给程序加断点进行缘由寻找,发现原来是HashMap的中服务器和终端双方对于一样的key存放顺序居然不同!服务器

在HashCode产生冲突的状况下,不一样的key在HashMap中存入的位置应该是相同的,即便在hashCode产生冲入,若是key-value put的顺序相同,其存放的位置也应该是相同的。ide

寻找,解决

因此问题就应该出在HashMap上,只能去查看Java和Android关于HashMap的源码了,发现二者的hashCode()方法居然不同,小小激动了一下,可仔细一看,发现Android只是优化Java中的hashCode()方法,使其更加易于阅读而已,但所运用的原理仍是同样的,真是=。=。
具体代码比较以下:函数

<!-- Android -->
@Override public int hashCode() {
    int hash = hashCode;
    if (hash == 0) {
        if (count == 0) {
            return 0;
        }
        final int end = count + offset;
        final char[] chars = value;
        for (int i = offset; i < end; ++i) {
            hash = 31*hash + chars[i];
        }
        hashCode = hash;
    }
    return hash;
}

<!-- Java-->
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;
}

无奈,我只能继续在源码里查看比较,最后发现原来是二者的默认构造函数不同,本质上就是二者的table大小不同,Java中的table默认大小是16×0.75=12(容量×负载因子),而Android中table的默认大小是2,因此即便是一样的字符串按一样的顺序放入HashMap中它们的key值存放顺序也会不同。优化

<!-- Android -->
private static final Entry[] EMPTY_TABLE
        = new HashMapEntry[MINIMUM_CAPACITY >>> 1];
//默认构造函数
public HashMap() {
    table = (HashMapEntry<K, V>[]) EMPTY_TABLE;
    threshold = -1; // Forces first put invocation to replace EMPTY_TABLE
}

<!-- Java -->
static final int DEFAULT_INITIAL_CAPACITY = 16;
static final float DEFAULT_LOAD_FACTOR = 0.75f;
//默认构造函数
public HashMap() {
    this(DEFAULT_INITIAL_CAPACITY,DEFAULT_LOAD_FACTOR);
}

其实仔细读源码会发现,在Android中所实现的HashMap类关于"阈值(threshold )"的设定也已经和Java不一样了,具体请看截取的源码:this

<!-- Android -->
//阈值固定取其table大小的3/4
threshold = (newCapacity >> 1) + (newCapacity >> 2); 

<!-- Java -->
//阈值取容量*负载因子或最大容量+1间的小值
threshold = (int)Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);

小结

因此总结来看HashMap在不一样平台或不一样语言中的实现细节是不同的,吃一堑,长一智,反正之后切记,牵扯到顺序时HashMap真的不适合!加密

做者:XycZero
查看原文:http://www.xyczero.com/blog/article/16/.code

相关文章
相关标签/搜索