The following code is a JUnit test function which fails upon execution.
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));
It uses the KGramPostingsEntry
class:
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;
}
}
As you can see, there is an equals()
function in the class that compares the tokenID
of the different KGramPostingsEntry
objects. It seems to me that this function is not used when calling containsAll()
in the test. Further experimentation seems to verify this to be true:
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));
Here, I'm inserting the same object in both lists. This test does not fail. As far as I've gathered, ArrayList
makes a copy object of the object sent to add()
, before storing a reference to that object. This means that the objects in the two List
s are not the same (even though they have the same tokenID
), and that containsAll()
does not check for object reference equality. But if it does not check for object reference equality and does not check the equals()
function defined in my code, what does it check? The only plausible option to me is that it checks for object value equality, and that the two objects stored in the first test example are somehow different (even though their only property is tokenID
, which is the same in both objects).
What is going on here? How can I make this test succeed the way I want it to?
Here the equals
declaration of Object
:
public boolean equals(Object obj)
(documentation). You're trying to override this method, but instead you overloaded it:
public boolean equals(KGramPostingsEntry other)
Notice how the argument type in your method is KGramPostingsEntry
, which differs from the argument type in Object.equals
, namely Object
. When a method has the same name but different argument types, it is overloaded, not overridden.
When the ArrayList
tries to compare its contents with equals
, it'll use the most applicable overridden version of Object.equals
. That unfortunately doesn't include your method.
Luckily the fix is easy: you need to implement your equals
method with an Object
argument:
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With