Overloading remove and the Integer Trap
DynamicArray<T> has one remove, by value:
// remove the first element equal to value; return whether anything was removed
public boolean remove(T value) {
int i = indexOf(value);
if (i == -1) {
return false;
}
remove(i);
return true;
}
Solution
// remove the element at a given index; return what was removed
public T remove(int index) {
T removed = arr[index];
for (int j = index; j < size - 1; j++) {
arr[j] = arr[j + 1];
}
size--;
arr[size] = null;
return removed;
}
Several methods may share a name as long as their parameter lists differ. Java resolves a call by matching the argument types against the parameter types, and it ignores parameter names and return type. With int elements, “remove this value” and “remove at this index” are both remove(int), the same signature, so only one can exist. With elements typed T, the two signatures are remove(T value) and remove(int index), which differ, so both compile.
Solution
It removes the element at index 2, the value 3, not the value 2. The literal 2 is a plain int. Both overloads can accept it: remove(int) takes it directly, and remove(Integer) (which is what remove(T) becomes here) would need it autoboxed first. Java prefers the overload that needs no conversion, so it picks remove(int).
To remove the value, pass an actual Integer so only remove(T) fits:
scores.remove(Integer.valueOf(2));