I have had a look at the Java Collection API. The Collection interface defines the remove method as follows:
public interface Collection<E> {
// other methods
boolean add(E e);
boolean remove(Object o);
}
You can see that the remove method’s parameter is of type Object
instead of the collection’s element type E
. I understand the logic behind this design decision: I prefer getting false rather than a ClassCastException
. It also relieves client code from casting objects prior to calling this method.
The weird thing, however, is in the implementation of the remove method by some collections. Take, for example, the ArrayList
implementation:
public class ArrayList<E> extends AbstractList<E> {
//Partial listing
public boolean remove(Object o) {
final Object[] es = elementData;
final int size = this.size;
int i = 0;
found: {
if (o == null) {
for (; i < size; i++)
if (es[i] == null)
break found;
} else {
for (; i < size; i++)
if (o.equals(es[i])) //heeeeeeeeer!!!!!!!!!
break found;
}
return false;
}
fastRemove(es, i);
return true;
}
}
Here, the implementation calls the equals method on the foreign object o
rather than on the “trusted” collection elements. Isn’t it safer to call the equals method on the elements of the collection (es[i].equals(o)
) instead? For instance, if o
is some malicious object that does not adhere to the equals contract, the remove method may remove random elements from the collection:
class MalObject {
@Override
public boolean equals(Object o) {
return true;
}
}
With the current remove implementation, calling list.remove(malObject)
would randomly remove elements from the list.
I can’t see any obvious reason why not to call the eequals
method on the collection elements instead. What is the reason behind this implementation, is there any benefit behind it?
Mohamed Nasser is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.