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

时间:2018-04-20 14:20:58

标签: java unit-testing arraylist junit

以下代码是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));

它使用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;
    }
}

如您所见,该类中有一个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));

在这里,我在两个列表中插入相同的对象。此测试不会失败。就我收集的内容而言,ArrayList在存储对该对象的引用之前,将对象的副本对象发送到add()。这意味着两个List中的对象不相同(即使它们具有相同的tokenID),并且containsAll()不检查对象引用相等性。但是,如果它没有检查对象引用相等性并且没有检查我的代码中定义的equals()函数,它会检查什么?对我来说唯一合理的选择是它检查对象相等,并且第一个测试示例中存储的两个对象以某种方式不同(即使它们唯一的属性是tokenID,两个对象都是一样的。)

这里发生了什么?如何以我想要的方式使测试成功?

2 个答案:

答案 0 :(得分:4)

equals方法没有正确的签名。它应该是

__exit__

答案 1 :(得分:4)

此处equals的{​​{1}}声明:

Object

documentation)。您正在尝试覆盖此方法,而是重载

public boolean equals(Object obj)

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

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

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

Object