我能否以不同的方式使indexOf比较对象?

5
我想使用indexOf,但是List中的对象不会是相等的对象,而是具有值相等性(即它们是等效的但不相等)。
我想让indexOf以一种不同于Object.equals方法的方式进行比较。我考虑重写equals方法,使用我的isEquivalent方法来代替,但我不确定如何做到这一点,甚至不知道是否可能。
我尝试了许多变化,但仍然出现错误:
List<CustomType> items{
        @Override
        public boolean equals(Object o)
        {
             return false;
        }
    }
    = //stuff to populate it

我还看过一个回答 (链接),其中讨论了EqualityComparer,Java 中是否有类似的东西?

还是有其他方式可以实现这个功能吗?


也许你收到错误是因为 equals 返回的是 boolean 而不是 void - OneCricketeer
@cricket_007 哈哈,糟糕了,现在已经修复了。不,那不是原因。 - Aequitas
也许可以添加你的 isEquivalent 方法。此外,从你这里的代码来看,你正在尝试覆盖 List 接口上的 equals 方法,而不是 CustomType 对象的。 - OneCricketeer
@cricket_007 问题不在于我的isEquivalent方法,因为即使我只返回false,也会出现相同的错误。你说的第二部分是什么意思?难道我不是在尝试重写列表上的equals方法,以便当调用items.indexOf时使用equals,而我发布的equals将被使用吗? - Aequitas
等于 b,或者你可以看到我提供的答案。 - OneCricketeer
显示剩余2条评论
3个回答

4
这是我的尝试。我使用了 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

或者

我之前在评论中想说的是,如果你重写了 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) >= 0; - Paul Boddington
@PaulBoddington - 是的。这也使得列表完全依赖于CustomType类。 - OneCricketeer
1
@Aequitas - 因为这是你的问题 :) “我可以让indexOf以不同的方式比较对象吗?” - OneCricketeer
我认为只覆盖equals会更简单,因为它只需要一行代码,而不是使用indexof。另外,当我将其设置为某些数据时,我该怎么做?我需要先创建一个新的List然后再添加吗? - Aequitas
好的,谢谢。我明白了。但这对我不起作用,因为在其他情况下我需要等于号成为默认值。 - Aequitas
显示剩余2条评论

3
缺少类似于“EqualityComparer”的东西,在我看来,是标准Java中最糟糕的事情之一。这意味着如果您想在集合(如ArrayList或HashSet)中使用对象,您只能使用一个相等的概念来执行indexOf和contains等方法。这非常非常令人恼火。这与“TreeSet”形成完全对比,它更加灵活,允许您使用“Comparator”来指定集合的排序方式。
我建议不要重写“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;
}

0

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接