起因

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

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

在HashCode产生冲突的情况下,不同的key在HashMap中存入的位置应该是相同的,即使在hashCode产生冲入,如果key-value put的顺序相同,其存放的位置也应该是相同的。

寻找,解决

所以问题就应该出在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不同了,具体请看截取的源码:

<!-- 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/.

HashMap在Android和Java中的不同实现的更多相关文章

  1. 【Android】java中调用JS的方法

    最近因为学校换了新的教务系统,想做一个模拟登陆功能,发现登陆的账号和密码有一个js脚本来进行加密 整理了一下java中执行JS的方法 智强教务 账号 密码 加密方法 var keyStr = &quo ...

  2. 关于在Android或Java中精度缺失的解决方法

    left,right是两个String类型的字符串,myres是一个double类型的变量. 如果我们用下面的语句把left,right先转换为double后直接加法的话,如果作3.3乘3之类的运算( ...

  3. Android及java中list循环添加时覆盖的问题-20171021

    鉴于新浪博客太渣,转到这来. 最近在工程设计时,使用list循环添加map对象发现,最终全部变为最后一个map的值,但是list的数值还是正确的,也就是说添加了N(list长度或者说循环的次数)个相同 ...

  4. Android(java)学习笔记186:对ListView等列表组件中数据进行增、删、改操作

    1.ListView介绍 解决大量的相似的数据显示问题 采用了MVC模式: M: model (数据模型) V:  view  (显示的视图) C: controller 控制器 入门案例: acit ...

  5. Android(java)学习笔记129:对ListView等列表组件中数据进行增、删、改操作

    1. ListView介绍 解决大量的相似的数据显示问题 采用了MVC模式: M: model (数据模型) V:  view  (显示的视图) C: controller 控制器 入门案例: aci ...

  6. hash表及Java中的HashMap与HashSet

    链接: http://alex09.iteye.com/blog/539545/ 当程序试图将一个 key-value 对放入 HashMap 中时,程序首先根据该 key 的 hashCode() ...

  7. java中的反射机制在Android开发中的用处

    JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反 ...

  8. 如何在JAVA中实现一个固定最大size的hashMap

    如何在JAVA中实现一个固定最大size的hashMap 利用LinkedHashMap的removeEldestEntry方法,重载此方法使得这个map可以增长到最大size,之后每插入一条新的记录 ...

  9. Java中List,ArrayList、Vector,map,HashTable,HashMap区别用法

    Java中List,ArrayList.Vector,map,HashTable,HashMap区别用法 标签: vectorhashmaplistjavaiteratorinteger ArrayL ...

随机推荐

  1. [CF 351B]Jeff and Furik[归并排序求逆序数]

    题意: 两人游戏, J先走. 给出一个1~n的排列, J选择一对相邻数[题意!!~囧], 交换. F接着走, 扔一硬币, 若正面朝上, 随机选择一对降序排列的相邻数, 交换. 若反面朝上, 随机选择一 ...

  2. 月見(つきみ) 夕(ゆう) SumiHui.墨虺

    造影早迎中秋,自己通过word设计的

  3. thinkphp中使用PHPEXCEL导入数据

    导入方法比较简单 但必须考虑到Excel本身单元格格式问题 例如以0开头的字符串读出来被去掉了前导0 成为float型而丢失一位 必须进行处理 <?php /** * Author lizhao ...

  4. Node.js异步处理CPU密集型任务

    Node.js异步处理CPU密集型任务 Node.js擅长数据密集型实时(data-intensive real-time)交互的应用场景.然而数据密集型实时应用程序并非仅仅有I/O密集型任务,当碰到 ...

  5. good page

    http://www.cnblogs.com/zrtqsk/category/540486.html

  6. 启动hadoop时候报错:localhost: ssh: Could not resolve hostname localhost: Temporary failure in name resolution”

    这个错误是由于配置文件没有配置好.解决方案如下: 1 打开profile文件 vim /etc/profile 2 在文件最后加入的内容应该如下(高亮的两句一般是大家缺少的): export JAVA ...

  7. SpringSecurity 在MVC 中的简单使用(翻译的,稍加改动)

    Spring Security允许开发人员轻松地将安全功能集成到J2EE Web应用程序中,它通过Servlet过滤器实现“用户自定义”安全检查. 在本教程中,我们将向您展示如何在Spring MVC ...

  8. jquery选择器取值和url正则匹配

    用到的简单jquery知识,简单总结一下,一是能加深自己的记忆,二是方便自己以后查看.常言道"好记性不如烂笔头",要养成常总结.常记录的好习惯.慢慢的发现jquery很有意思,很强 ...

  9. 11月15日jquery学习笔记

    1.属性 jQuery对象是类数组,拥有length属性和介于0~length-1之间的数值属性,可以用toArray()方法将jQuery对象转化为真实数组. selector属性是创建jQuery ...

  10. Android中的Adapter 详解

    http://blog.csdn.net/tianfeng701/article/details/7557819 (一) Adapter介绍 Android是完全遵循MVC模式设计的框架,Activi ...