【问题标题】:IEqualityComparer interface in JavaJava中的IEqualityComparer接口
【发布时间】:2011-06-17 18:59:17
【问题描述】:

更具体地说,我想要一个接口来比较只能比较是否相等的对象[例如复数],但它们没有总顺序。 它应该有 [注意它只返回一个布尔值是/否]

boolean Equals(T object1, T object2);

和一个哈希码函数。因此,当我使用对象将它们分配到桶中时说收集“相等”的对象,2个“相等”的对象不会最终出现在两个不同的桶中。

int getHashCode(T object);

Java 有吗?我搜了没找到。

我正在尝试在 Hadoop Map Reduce 中使用它来将“相等”的对象分配给同一个 reduce 作业,以便我可以对所有“相等”的对象进行操作。我只关心对象是否相等,不需要全序。但是如果两个对象相等,它们应该具有相同的哈希码。否则他们最终会从事两个不同的 reduce 工作。

请注意,我知道对象的等号和哈希码。但我想要一个外部比较器,它说只取决于对象的一部分。所以对象的平等概念和我的不同。

【问题讨论】:

  • 我不知道 C# 类比,但你检查过Object 类吗?它有equals()hashCode() 方法。它基本上在每个类中都是继承的(并且是可覆盖的)。 download.oracle.com/javase/6/docs/api/java/lang/Object.html 或者您可能需要Comparatordownload.oracle.com/javase/6/docs/api/java/util/Comparator.html
  • 不 - 我想要一个外部比较器 - 我对“平等”的概念与对象本身的平等不同。假设我只想比较对象的一部分,但对象本身在所有字段上实现相等。
  • 标准 java.util 不支持类似的功能。
  • 我认为Comparator 无论如何都接近了。它不返回boolean,但您可以检查它是否返回0
  • @Balsu - 是的 - 那是我的第一次尝试。但不幸的是比较器没有哈希码。所以我不知道如何将对象分配到桶中——因为只有它知道比较器的相等概念,所以我所做的任何分配都可以将相等的对象放入不同的桶中。

标签: java collections


【解决方案1】:

在 Java 中没有用于此的内置类型。这是收藏设计中的一个“漏洞”,IMO。恐怕有一个特定于字符串的Collator 类,它已经非常接近了。

无法自定义内置地图以使用特定类型的相等比较,更糟糕的是。 完全合理想要这个功能,但它还没有出现真的很痛苦。

当然,您可以创建自己的此类界面,并编写您自己的地图变体来使用它...但必须这样做很糟糕:(

【讨论】:

  • 是的 - 我最终定义了自己的 EqualityComparator,它是 IEqualityComparer 的精确副本,因为我只需要我的 map-reduce 组件和用户之间的合同。对于尝试使用 HashSet 等的人来说,这将是非常痛苦的。
  • IIRC,有一些实现,Google for "Equalator"。
【解决方案2】:

你想要的类型是 Guava 的Equivalence。但是,您可能会感到失望,因为在 Java 中 CollectionMap 是根据 Object.equals 相当严格地指定的,并且您不会在 Guava 中找到使用替代等效项的实现。但是,您可以使用 myEquivalence.wrap(myObject) 稍微模拟一下这种行为。

【讨论】:

    【解决方案3】:

    我建议使用基于函数的方法来生成像MultiMaps.index() method in Google collections(现在的番石榴)那样的桶。他们使用 Function<V,K>V 类型的对象映射到 K 类型的键(在您的情况下是存储桶)。

    【讨论】:

    • 有趣的是,Guava 为此定义了Equivalence<T> 接口,但并未在其任何 Map 实现中使用它。
    • @finnw - 这正是我想要的。但我不想只为那个界面使用那个库。但很高兴知道。下次我已经对它有依赖时,我会使用它。
    【解决方案4】:

    最后我选择写我在类似情况下所做的事情。 如果我需要特殊的相等/哈希 - 例如保持弱引用。您可以像这样包装密钥。总体而言,它与接口方法没有太大区别,但它创建了哑实例(如用于存储桶条目的 HashMap/Hashtable)。您可能需要对 keySet() 等进行额外的解包...

    package t1;
    
    public abstract class KeyX<Key> implements java.io.Serializable {
        private static final long serialVersionUID = 0l;
    
        final Key key;
        final int hash;
        protected KeyX(Key key){
            this.key = key;
            this.hash = hashCode(key);
        }
    
        protected abstract int hashCode(Key key);
    
        //Key, Key will be way too strict and it'd required, key.getClass().isInstance(y) prior calling
        protected abstract boolean equals(Key x, Object y);
    
        @Override
        public final boolean equals(Object obj) {
            if (obj==this)
                return true;
            if (!(obj instanceof KeyX)){
                return false;
            }
            final KeyX<?> other = (KeyX<?>) obj;
            return this.key==other.key ||  (hash==other.hash && other.key!=null  && equals(this.key, other.key)); 
    
        }
    
        @Override
        public final int hashCode() {
            return hash;
        }
    
        public final Key unwrap(){
            return key;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-04
      • 2012-08-21
      • 2016-08-28
      • 2011-11-16
      • 1970-01-01
      • 2012-10-23
      相关资源
      最近更新 更多