嵌套映射或java中的组合键

我需要一个Map来在Java中创建一个缓存,以获得相同的值,我有两个String键。 我的问题是,最好制作嵌套地图(每个键一个)或者使用两个字符串制作某种类型的自定义键?

访问缓存上的数据将始终使用两个密钥访问,我不需要通过这两个密钥中的任何一个对其进行分组。

然后,如果更好地结合字符串键只有一个什么更好?

  • 使用自定义getHash方法的自定义类。 但那么问题是哈希函数实现了什么?
  • 简单地将两个字符串连接在一起。 例如:

    cache.put(key1 + key2,value)

您可以制作嵌套映射或使用定义hashCode()的自定义类。

连接键通常不是一个好主意,最终可能会发生冲突,例如键122以及键122 。 他们映射到相同的值122

如果你总是使用两个键,使用单个Map总是会更有效率,你可以随时定义你自己的适配器到地图,它将采用两个参数:

 public class MyCache { private Map cache = new HashMap(); public Object getObject(Object key1, Object key2){ return cache.get(new MyKey(key1, key2)); } public void putObject(Object key1, Object key2, Object value){ cache.put(new MyKey(key1, key2), value); } } 

请记住在自定义键类中定义equals()hashCode() (如果需要,添加对null的检查)。

 public int hashCode() { int result = 17; result = 37 * result + keyA.hashCode(); result = 37 * result + keyB.hashCode(); return result; } public boolean equals(Object another) { return another.keyA.equals(keyA) && another.keyB.equals(keyB); } 

您可能想要考虑Guava的Table类。 它们实现了每个值有两个键的Map 。 根据您的要求,这可能提供比复合键更可读的解决方案。

 Table 

最好是制作嵌套地图(每个键一个)或者使用两个字符串制作某种类型的自定义键?

具有复合键类型的单个散列表可以具有更好的引用局部性。 它几乎肯定会占用更少的内存并且速度更快,但多少取决于您的应用程序。

设计自定义散列函数可能很棘手,但您可以从一个函数开始,该函数只接受复合键成员的已定义哈希值并将它们一起异或。 您也可以采用字符串路由,但请确保将成员与它们之间的某些标记连接起来(例如“ ”),这些标记不太可能出现在它们之间。

使用组合键对我来说似乎更合乎逻辑,并且更易于使用(您不必担心嵌套映射被实例化)。

关于键的组合,请使用自定义类。 它在语义上更有意义,如果你有类似的字符串,可以防止冒号。 如果您有密钥["ab", "c"]和密钥["a", "bc"]则可能会出现这种情况。

请记住,在编写自定义类时,需要正确编写equalshashCode方法,否则缓存可能无法正常工作(并且可能会遇到性能问题)。

我在缓存系统中遇到了类似的问题,需要使用方法参数来生成密钥。 我最后编写了一个类似于Xavi答案的包装类。

 public final class ArrayWrapper { private final Object[] array; public ArrayWrapper(final Object... array) { this.array = array; } public Object[] getArray() { return this.array; } public boolean equals(Object o) { if (o == null) return false; if (o == this) return true; if (o instanceof ArrayWrapper) { return Arrays.equals(this.array, ((ArrayWrapper)o).array); } return false; } private int hashCode(Object o) { if (o == null) return 0; return o.hashCode(); } public int hashCode() { int sum = 17; if (this.array != null) for(int i = 0;i 

创建一个新的包装器并将其用作Map的键。 您还可以编写自定义映射并重载get和put方法以接受数组(也用于获取vararg),而不必手动包装它。

我认为使用嵌套地图不是最佳方式。 我同意你的第二个想法 – 使用覆盖hashCode实现自定义类

 public int hashCode(){ return str1+str2.hashCode(); } 

equals

 public boolean equals(Object o){ //compare both keys here } 

另外,不要忘记在存储对象的类中重写相同的方法。

然后,在[“ab”,“c”]的情况下,您将具有相同的哈希码,但是不同的等于结果