HashMap 和 ArrayList 有什么区别?兼谈面试题的选择

面试不是为了考到别人,是为了找到我们需要的人,面试官也要换位思考。

Q: HashMap 和 ArrayList 有什么区别?
A: ... (一脸懵逼,这根本就是两种东西好嘛)

朋友面试归来,跟我提及上面的面试题,问我怎么看。有什么区别?一个是 K/V 类型,一个是列表类型,除了都是 Java Collection Framework 成员,是容器外,从 API 接口看,完全没有共同点。我一时也很茫然,不知道面试官在考察什么,直到我开始想我是怎么用 ArrayList 的。

在游戏项目中,大量的数据是常驻内存的,比如在线玩家的数据。这就需要在内存中对这些数据集合做管理,通常是使用 HashMap 或者 ArrayList(数组)。想到这一层,这个问题开始变的有意义,只要熟悉这两个数据结构,就很容易看出区别来。我这里试着列举一些。

  • 查询 ArrayList 只能用数字索引,查询 HashMap 不限数字索引
  • 数据保存到 ArrayList 必须用紧凑的索引,否则稀疏的数组会造成很大浪费,而保存到 HashMap 中空间使用效率与 key 是否稀疏无关
  • 使用 ArrayList 管理数据时,一般需要维护一个实际 key 到 index 的映射,HashMap 不需要这个映射
  • 为避免 hash 冲突导致的效率下降,HashMap 的空间使用率低于 ArrayList,在数据量较大时将产生比较明显的影响
  • 虽然时间复杂度都是 O(1),ArrayList 的常数时间低于 HashMap 的常数时间

总体比较下来就是 ArrayList 的内存使用效率更高,但是需要编写更多代码,只有在管理大量 key 时有优势。也可以把 ArrayList 理解为只能使用连续数字索引作为 key 的 HashMap。在 php 中,map 即是数组,是一回事,但对于 Java 程序员来说,不是一下子就能想到。

到这一步,问题似乎解决了,但这是一道好的面试题吗?

面试官认为自己提了一个简单的问题,但对于被试者来说,在短时间内一下可能一下没有想到,在简单问题上栽了跟头。这对于面试官和被试者都不是好事,毕竟面试的最终目的是找到合适的人,尽可能的让被试者展示自己的能力,才是符合目标的做法。

我认为做到下面这些就足够了

  1. 题目是清晰的,聚焦的,而非宽泛的。过于宽泛的问题往往够写一本书,一会导致出现浑水摸鱼的情况,二会导致回答的深度不够。比如,如何对 JVM 调优 vs 游戏服务器进程堆为 4g+,如何设置参数减少 gc 时的 STW 时间。
  2. 题目最好从一个问题出发,询问解决方案,而不是从一个具体的结果出发,反向推出题目,这种情况容易导致背景缺失。做一个项目要很久,要尽量去除偶然因素。比如文初的这个题目,更好的问法是你是如何管理游戏中的对象的,用的什么数据结构,选择的依据和原因。
  3. 如果要考察实战能力,比如 debug 的能力,最好是自己解决过的线上问题。
  4. 如果要考察跟同事合作的能力,比如面试游戏程序员时,可以把自己想象成策划。
  5. 有条件的话最好当场写代码,毕竟 talk is cheap

以上做法仅适用于小的团队。