由于这些日子以来,硬件变得非常便宜,并且具有非常大的可用内存。为什么我们不能在所有情况下都通用使用像HashMap这样的通用DataStructure?如果不是,是否有简短的指导原则来了解在哪种情况下要使用哪个DataStructure?
最佳答案
(编辑:此答案假设您在存储key -> value
映射的上下文中询问。如果您的数据不自然地代表映射,例如字符串列表,则任何一种Map
都是一种不好的方法无论是在性能方面还是在使其他查看您的代码的其他人困惑的方面,都可以代表它。)
一般来说,可以。如果您使用的地图带有具有不错的hashCode()
实现的不可变键(例如String
,任何自动装箱的原语),那么HashMap通常是完全可以接受的。
但是,存在不同的数据结构是有原因的-它们都提供不同的性能(有时还包括正确性)语义,因此在某些情况下,您可能希望选择其他结构。
例如,如果您希望在迭代过程中以特定顺序访问地图条目(基于键),则可以使用TreeMap
。如果希望迭代顺序基于插入顺序,请使用LinkedHashMap
。如果您希望在简单的并发访问(具有缺少情况的语义)下获得良好的性能,请使用ConcurrentHashMap
。如果您的键是枚举,那么EnumMap
是最有效的实现方法。如果要将密钥存储为弱引用,请使用WeakHashMap
。如果要基于所使用的确切对象执行查找(使其对于可变键很安全),请使用IdentityHashMap
。
更不用说,如果您知道(但无法更改)您的键使用的hashCode()
方法执行不佳,尤其是如果它与equals不一致,那么HashMap
可能仍然是一个糟糕的选择。
并且,您可能希望数据结构具有许多其他可能的功能,这些功能是无法涵盖的,这些功能包括(但不限于):
不是键排序或插入顺序的特定迭代顺序
大小限制(尤其是可自定义选择要踢出的条目)
按键的软/虚拟引用
对不存在的键执行get()
时的延迟初始化
等等。如果您自己的域对象具有某些属性,而特定的Map
实现可以利用该属性来实现更快/更清洁/增强的性能(这是通用库实现永远无法实现的),则这尤其可能。
解决“硬件便宜”的说法-这是正确的,但是程序员的时间和用户的时间不是。在某些情况下,应用程序的关键循环可能涉及许多映射查找,因此加快这些查找的速度将对性能产生显着影响。当然,通常情况并非如此,但是如果是这样,则针对特定情况选择性能更好的地图(想到的一个简单示例是在适当的地方使用EnumMap
)将产生性能提升-这可以非常重要。
或者,某些地图实现只是使周围的代码更易于编写,更易于理解,并且不太可能包含错误。这里的一个例子可能是延迟初始化映射的情况(类似于Google Collections的ComputingMap)。尽管您可以围绕标准HashMap
用惰性初始化语义编写一些代码,但是通过将所有这些逻辑打包在map实现本身中,可以更容易地测试其正确性-并且客户端逻辑也更加简单。
因此,便宜的硬件/空间并不意味着HashMaps对于所有事物都是最佳的。实际上,如果有什么话,那就是反驳-与您可能会采用的更量身定制的替代方案相比,HashMap具有相当的空间效率。有了许多廉价的空间,完全有可能在时间与空间之间进行权衡,存储大量信息以加快查找速度。
请注意,我将您的问题解释为“为什么有时有时会使用Map
的其他类?”而不是“您应该在何时使用其他哪个Maps
?”如果是后者,请随意改写或提出另一个更具体针对此的问题。
关于java - 在Java中,为什么我们不能在所有情况下都使用通用的通用数据结构(如HashMap)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4737364/