ArrayList.containsAll 不使用我的自定义 equals 函数

Sah*_*and 4 java junit unit-testing arraylist

以下代码是 JUnit 测试函数,执行失败。

List<KGramPostingsEntry> a = new ArrayList<KGramPostingsEntry>();
List<KGramPostingsEntry> b = new ArrayList<KGramPostingsEntry>();
KGramPostingsEntry entry = new KGramPostingsEntry(1);
a.add(entry);

entry = new KGramPostingsEntry(1);
b.add(entry);

assertTrue(a.containsAll(b));
Run Code Online (Sandbox Code Playgroud)

它使用以下KGramPostingsEntry类:

package ir;

public class KGramPostingsEntry {
    int tokenID;

    public KGramPostingsEntry(int tokenID) {
        this.tokenID = tokenID;
    }

    public KGramPostingsEntry(KGramPostingsEntry other) {
        this.tokenID = other.tokenID;
    }

    public String toString() {
        return tokenID + "";
    }
    public boolean equals(KGramPostingsEntry other) {
        if(other.tokenID == this.tokenID) {
            return true;
        }
        return false;
    }
}
Run Code Online (Sandbox Code Playgroud)

equals()正如您所看到的,类中有一个函数可以比较tokenID不同KGramPostingsEntry对象的值。我感觉containsAll()测试中调用的时候并没有使用这个函数。进一步的实验似乎证实了这一点:

List<KGramPostingsEntry> a = new ArrayList<KGramPostingsEntry>();
List<KGramPostingsEntry> b = new ArrayList<KGramPostingsEntry>();
KGramPostingsEntry entry = new KGramPostingsEntry(1);
a.add(entry);
b.add(entry);

assertTrue(a.containsAll(b));
Run Code Online (Sandbox Code Playgroud)

在这里,我在两个列表中插入相同的对象。这个测试不会失败。据我所知,在存储ArrayList对该对象的引用之前,先创建发送到的对象的副本对象add()。这意味着两个 s 中的对象List不相同(即使它们具有相同的tokenID),并且containsAll()不会检查对象引用是否相等。但是,如果它不检查对象引用相等性,也不检查equals()我的代码中定义的函数,那么它会检查什么?对我来说唯一合理的选择是它检查对象是否相等,并且第一个测试示例中存储的两个对象在某种程度上有所不同(即使它们唯一的属性是tokenID,这在两个对象中是相同的)。

这里发生了什么?我怎样才能让这个测试按照我想要的方式成功?

pkp*_*pnd 5

这里equals声明Object

public boolean equals(Object obj)
Run Code Online (Sandbox Code Playgroud)

文档)。您试图重写此方法,但您却重载了它:

public boolean equals(KGramPostingsEntry other)
Run Code Online (Sandbox Code Playgroud)

请注意方法中的参数类型KGramPostingsEntry,它与 中的参数类型不同Object.equals,即Object。当一个方法具有相同的名称但不同的参数类型时,该方法被重载,而不是被覆盖。

ArrayList尝试将其内容与 进行比较时equals,它将使用最适用的覆盖版本Object.equals。不幸的是,这不包括你的方法。

幸运的是,修复很简单:您需要使用参数equals来实现您的方法Object

public boolean equals(Object obj) {
    if(obj == null || !(obj instanceof KGramPostingsEntry)) {
        return false;
    }
    KGramPostingsEntry other = (KGramPostingsEntry) obj;
    if(other.tokenID == this.tokenID) {
        return true;
    }
    return false;
}
Run Code Online (Sandbox Code Playgroud)