由于 JDK 实现[Linked]HashMap
不允许您覆盖equals
/hashCode
实现,因此唯一的其他方法是:
像这样的包装对象:
class A {
private final String fieldA; // equals/hashCode based on that field.
private final String fieldB; // equals/hashCode based on that field.
}
class B {
private A a;
public int hashCode() {return a.fieldA.hashCode();}
public boolean equals(Object o) {... the same ... }
}
Map<B, Value> map = new HashMap<B, Value>();
map.put(new B(new A("fieldA", "fieldB")), new Value(0));
好吧,有更多的吸气剂/构造器。
这可能很烦人,并且可能存在一些库(如 Guava),它允许给出一个 equals/hashCode 方法,就像你可以给出一个Comparator
to一样TreeMap
。
您将在下面找到一个示例实现,它指出了如何装饰现有地图。
将 aTreeMap
与特定的Comparator
. 另一个答案指向它,但我会说你需要正确定义 aComparator
因为这可能会导致问题:如果你compareTo
的方法在达到相等时返回 0 ,而在其他情况下返回 1 ,这意味着没有自然排序。您应该尝试找到一个,或使用包装器对象。
如果您想接受挑战,您可以使用委托/装饰创建一个基本实现HashMap
(这可能是另一种映射,例如LinkedHashMap
):
public class DelegatingHashMap<K,V> implements Map<K,V> {
private final BiPredicate<K,Object> equalsHandler;
private final IntFunction<K> hashCodeHandler;
private final Map<Wrapper<K>,V> impl = new HashMap<>();
public DelegatingHashMap(
BiPredicate<K,Object> equalsHandler,
IntFunction<K> hashCodeHandler
) {
this.equalsHandler = requireNonNull(equalsHandler, "equalsHandler");
this.hashCodeHandler= requireNonNull(hashCodeHandler, "hashCodeHandler");
}
public Object get(K key) {
Wrapper<K> wrap = new Wrapper<>(key);
return impl.get(wrap);
}
...
static class Wrapper<K2> {
private final K2 key;
private final BiPredicate<K> equalsHandler;
private final IntFunction<K> hashCodeHandler;
public int hashCode() {return hashCodeHandler.apply(key);}
public boolean equals(Object o) {
return equalsHandler.test(key, o);
}
}
}
以及使用地图的代码:
DelegatingHashMap<String, Integer> map = new DelegatingHashMap<>(
(key, old) -> key.equalsIgnoreCase(Objects.toString(o, "")),
key -> key.toLowerCase().hashCode()
);
map.put("Foobar", 1);
map.put("foobar", 2);
System.out.println(map); // print {foobar: 2}
但也许最好的(对于内存)是重写HashMap
直接使用处理程序而不是包装器。