不同Activity实例的Object.hashCode()返回相同值问题咨询
问题描述
按照常规认知,除哈希碰撞场景外,不同对象实例的Object.hashCode()应当几乎互不相同。开发中观察到Android模拟器运行Activity时出现如下不符合预期的现象:
- 每次从Android Studio运行Activity,即便关闭模拟器、Android Studio甚至重启Windows10电脑,hashCode都保持一致,仅当对模拟器执行冷启动时hashCode才会变化;
- 同一个Activity实例在经历
onStart、onResume、onPause、onStop、onRestart生命周期循环时,hashCode不会发生变化; - 通过返回键关闭应用后重新在模拟器打开,hashCode会发生变化;
- 从最近任务列表划走杀死应用后重新启动,hashCode会变回首次启动时的数值。
原因解释
基础前提
- 按照Java语言规范要求,同一个对象实例的
hashCode()返回值在对象的整个生命周期内必须保持不变,这是所有JVM系运行环境都需要遵守的规则。 - 目前Android ART虚拟机的
Object.hashCode()默认实现并非基于对象内存地址,而是在该方法第一次被调用时,生成一个伪随机数存入对象头,后续调用直接返回该值。而生成伪随机数序列的种子,是在应用进程启动时一次性生成的。
各现象对应说明
- 冷启动才会变更hashCode的原因
Android模拟器默认开启了快速启动快照功能,常规关闭模拟器后再次启动,会直接加载之前保存的系统运行快照,整个系统的运行状态、所有全局随机数种子都和快照保存时完全一致。因此每次启动应用时,应用进程拿到的hashCode伪随机序列种子固定,生成的Activity实例hashCode自然不会变化。只有执行冷启动时,模拟器会重新初始化整个系统环境,全局随机种子重置,后续生成的hashCode才会发生变化。
- 同实例生命周期内hashCode不变的原因
该现象完全符合Java规范要求,生命周期循环过程中Activity实例始终没有被销毁重建,是同一个对象,hashCode当然不会发生变化。
- 返回键关闭再打开hashCode变更的原因
按返回键关闭应用时,仅会销毁当前的Activity实例,应用进程默认不会被系统杀死,仍在后台存活。重新打开应用时,会在已存活的原有进程中创建新的Activity实例,此时伪随机序列已经推进到后续位置,新实例生成的hashCode自然和之前的实例不同。
- 划杀应用重启后hashCode恢复初始值的原因
从最近任务划走应用会彻底销毁整个应用进程,再次打开应用时系统会重新创建新的应用进程。由于模拟器没有执行冷启动,全局随机种子没有变化,新进程拿到的hashCode伪随机序列种子和首次启动应用时的种子完全一致,新生成的Activity实例hashCode就会和首次启动的数值相同。
内容的提问来源于stack exchange,提问作者Alexey Krachkovsky
相关产品推荐
相关产品推荐

