【问题标题】:Can I make indexOf compare objects in a different way?我可以让 indexOf 以不同的方式比较对象吗?
【发布时间】:2015-11-30 21:46:52
【问题描述】:

我想使用indexOf,但List 中的对象不是相等的对象,但它们的值相等(即它们相等但不相等)。

我想让indexOf 以不同于Object.equals 方法的方式进行比较。我正在考虑重写 equals 方法以使用我的 isEquivalent 方法,但我不确定如何做到这一点,如果可能的话。

我已经尝试了很多变体,但总是出错:

List<CustomType> items{
        @Override
        public boolean equals(Object o)
        {
             return false;
        }
    }
    = //stuff to populate it

我还看到this answer 他们谈论 EqualityComparer 在 java 中有类似的东西吗?

或者有没有其他方法可以做到这一点?

【问题讨论】:

  • 也许您遇到错误是因为equals 返回boolean 而不是void
  • @cricket_007 哈哈哎呀,现在解决了。不,这不是原因
  • 也许添加您的isEquivalent 方法。此外,根据您在此处的内容,您试图覆盖 List 接口上的 equals,而不是 CustomType 对象。
  • @cricket_007 问题不在于我的 isEquivalent 方法,因为如果我只返回 false,它就是同一种错误。你说的第二部分是什么意思?我不是在尝试覆盖列表上的等号,以便在调用使用等号的 items.indexOf 时,它会使用我发布的等号,对吗?
  • 不,按照您的编写方式,您正在为 List 定义 equals。例如,您需要(格式较差)class CustomType { @Override boolean equals(Object o) { } },因为indexOf 在它包含的对象上使用equals

标签: java equals equality indexof


【解决方案1】:

这是我的破解之道。我使用了ArrayList,因为 List 是一个接口,您需要覆盖所有方法。

List<CustomType> customList = new ArrayList<CustomType>() {
    @Override
    public int indexOf(Object o) {
        if (o instanceof CustomType) {
            for (int i = 0; i < this.size(); i++) {
                CustomType c = (CustomType) o;
                if (c.isEquivalent(this.get(i))) {
                    return i;
                }
            }
        }
        return -1;
    }
};
// use indexOf like normal, but beware of side-effects as mentioned in the comments

或者

我之前在 cmets 中试图说的是,如果您覆盖 List.equals,这意味着您将 List 对象与另一个对象进行比较,而不是列表中的对象。要按照您的要求进行操作,您需要这样做。

class CustomType {

    public boolean isEquivalent(CustomType ct) {
        return true; // TODO: Implement this
    }

    @Override
    public boolean equals(Object obj) {
        // TODO: Implement this
        if (obj instanceof CustomType) {
            return this.isEquivalent((CustomType) obj); 
        }
        return false;
    }

    @Override
    public int hashCode() {
        return super.hashCode(); // TODO: Implement this
    }
}

public static void main(String args[]) {
    List<CustomType> lst = new ArrayList<CustomType>();
    // use indexOf like normal
}

【讨论】:

  • 这种事情的麻烦是有很多后果,你必须研究ArrayList的源代码才能知道它们是什么。例如,它也改变了contains 的行为,因为ArrayList 当前将contains 实现为return indexOf(o) &gt;= 0;
  • @PaulBoddington - 是的。它还使列表完全依赖于 CustomType 类。
  • 我不明白为什么我必须覆盖 indexOf 而不是这里的等于??
  • @Aequitas - 因为那是你的问题 :) “我可以让 indexOf 以不同的方式比较对象吗”
  • 我认为覆盖 equals 会更简单,因为它只有一行而不是 indexof 否?另外,当我让它等于一些数据时,我该怎么做,或者我必须先创建一个新列表然后添加到它?
【解决方案2】:

在我看来,缺少像 EqualityComparer 这样的东西是标准 java 最糟糕的事情之一。这意味着,如果您想在一个集合中使用对象,例如ArrayListHashSet,您只需要一种方法,例如indexOfcontains。这非常非常烦人。它与TreeSet 完全相反,后者更加灵活,允许您使用ComparatorSet 指定您想要的顺序。

我建议不要覆盖 indexOf 来表示与人们期望不同的东西。这可能会导致错误和混乱。此外,您可能希望在某些时候能够使用具有通常含义的indexOf

相反,您可以编写自己的EqualityComparer 接口

public interface EqualityComparer<E> {

    boolean areEqual(E e1, E e2);

    int hash(E e);  // Not needed for indexOf, but very useful in general
}

然后你可以像这样写一个静态方法indexOf

public static <E> int indexOf(List<? extends E> list, E item, EqualityComparer<? super E> comparer) {
    for (int i = 0; i < list.size(); i++)
        if (comparer.areEqual(list.get(i), item))
            return i;
    return -1;
}

【讨论】:

    【解决方案3】:

    在您的自定义对象中覆盖 equals() 和 hashcode()。如果两个对象相等,那么它们的哈希码也应该相等。

    【讨论】:

      猜你喜欢
      • 2012-09-07
      • 2015-03-14
      • 1970-01-01
      • 1970-01-01
      • 2020-11-03
      • 2013-03-05
      • 1970-01-01
      • 1970-01-01
      • 2010-09-22
      相关资源
      最近更新 更多