当前位置:  开发笔记 > 编程语言 > 正文

为什么不允许外部接口为HashMap提供hashCode/equals?

如何解决《为什么不允许外部接口为HashMap提供hashCode/equals?》经验,为你挑选了3个好方法。

随着TreeMap它的琐碎,提供自定义Comparator,从而覆盖所提供的语义Comparable添加到地图中的对象.HashMap然而,不能以这种方式控制; 提供哈希值和相等性检查的函数不能"侧载".

我怀疑设计界面并将其改装成HashMap(或新类)既简单又有用?这样的事情,除了更好的名字:

  interface Hasharator {
    int alternativeHashCode(T t);
    boolean alternativeEquals(T t1, T t2);
  }

  class HasharatorMap {
    HasharatorMap(Hasharator hasharator) { ... }
  }

  class HasharatorSet {
    HasharatorSet(Hasharator hasharator) { ... }
  }

在不区分大小写Map的问题得到了平凡解:

 new HasharatorMap(String.CASE_INSENSITIVE_EQUALITY);

这是可行的,还是你能看到这种方法的任何根本问题?

该方法是否在任何现有(非JRE)库中使用?(尝试谷歌,没有运气.)

编辑:hazzen提出的很好的解决方法,但我担心这是我试图避免的解决方法......;)

编辑:更改标题不再提及"比较器"; 我怀疑这有点令人困惑.

编辑:与业绩有关的已接受答案; 我会喜欢更具体的答案!

编辑:有一个实现; 看下面接受的答案.

编辑:改写第一句话,以更清楚地表明它是我正在进行的侧面加载(而不是排序;排序不属于HashMap).



1> Lukas Eder..:

对你来说有点晚了,但对于未来的访问者来说,可能值得知道commons-collections有一个AbstractHashedMap(3.2.2和4.0中的泛型).您可以覆盖这些受保护的方法以实现所需的行为:

protected int hash(Object key) { ... }
protected boolean isEqualKey(Object key1, Object key2) { ... }
protected boolean isEqualValue(Object value1, Object value2) { ... }
protected HashEntry createEntry(
    HashEntry next, int hashCode, Object key, Object value) { ... }

这种替代的示例实现HashedMap是公共的集合自身的IdentityMap(只到3.2.2的Java有其自己的自1.4).

这不如为实例提供外部" Hasharator" 那么强大Map.您必须为每个散列策略实现一个新的映射类(组合与继承反击......).但它仍然很好知道.



2> Jon Skeet..:

.NET通过IEqualityComparer(对于可以比较两个对象的类型)和IEquatable(对于可以将自己与另一个实例进行比较的类型)来实现.

实际上,我认为在java.lang.Object或System.Object中定义相等和哈希码是错误的.特别是平等很难用继承有意义的方式来定义.我对博客有意义......

但是,基本上这个想法是合理的.



3> Craig P. Mot..:

HashingStrategy是您正在寻找的概念.它是一个策略接口,允许您定义equals和hashcode的自定义实现.

public interface HashingStrategy
{
    int computeHashCode(E object);
    boolean equals(E object1, E object2);
}

你不能使用HashingStrategy内置HashSetHashMap.GS Collections包括一个调用UnifiedSetWithHashingStrategy的java.util.Set和一个调用的java.util.Map UnifiedMapWithHashingStrategy.

我们来看一个例子.

public class Data
{
    private final int id;

    public Data(int id)
    {
        this.id = id;
    }

    public int getId()
    {
        return id;
    }

    // No equals or hashcode
}

以下是设置UnifiedSetWithHashingStrategy和使用它的方法.

java.util.Set set =
  new UnifiedSetWithHashingStrategy<>(HashingStrategies.fromFunction(Data::getId));
Assert.assertTrue(set.add(new Data(1)));

// contains returns true even without hashcode and equals
Assert.assertTrue(set.contains(new Data(1)));

// Second call to add() doesn't do anything and returns false
Assert.assertFalse(set.add(new Data(1)));

为什么不用一个MapUnifiedSetWithHashingStrategy使用a的一半内存UnifiedMap,和a 的内存的四分之一HashMap.有时你没有方便的密钥,必须创建一个合成的密钥,就像一个元组.这会浪费更多的记忆.

我们如何执行查找?请记住,集合有contains(),但没有get().除了UnifiedSetWithHashingStrategy实现Pool之外Set,所以它还实现了一种形式get().

这是处理不区分大小写的字符串的简单方法.

UnifiedSetWithHashingStrategy set = 
  new UnifiedSetWithHashingStrategy<>(HashingStrategies.fromFunction(String::toLowerCase));
set.add("ABC");
Assert.assertTrue(set.contains("ABC"));
Assert.assertTrue(set.contains("abc"));
Assert.assertFalse(set.contains("def"));
Assert.assertEquals("ABC", set.get("aBc"));

这显示了API,但它不适合生产.问题是HashingStrategy经常委托String.toLowerCase()创建一堆垃圾字符串.以下是如何为不区分大小写的字符串创建有效的散列策略.

public static final HashingStrategy CASE_INSENSITIVE =
  new HashingStrategy()
  {
    @Override
    public int computeHashCode(String string)
    {
      int hashCode = 0;
      for (int i = 0; i < string.length(); i++)
      {
        hashCode = 31 * hashCode + Character.toLowerCase(string.charAt(i));
      }
      return hashCode;
    }

    @Override
    public boolean equals(String string1, String string2)
    {
      return string1.equalsIgnoreCase(string2);
    }
  };

注意:我是GS系列的开发人员.

推荐阅读
无名有名我无名_593
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有