Помните, что если вы не переопределите метод equals (), то два объекта вашего типа будут равны только в том случае, если они являются одинаковым экземпляром этого объекта. Класс ArrayList использует этот метод для проверки того, что он содержит данный объект. Кроме того, вам необходимо точно соответствовать сигнатуре, что означает, что он должен принимать объект в качестве параметра, а не Foo.
Кроме того, контракт Object предусматривает, что вы должны переопределять hashCode () всякий раз, когда переопределяете equals (). Если вы этого не сделаете, то HashMap или HashSet не будут идентифицировать ваши два объекта как равные, даже если это делает ArrayList (HashMap проверяет идентичные хэши, а затем вызывает equals () для их проверки на фактическое равенство). Таким образом, если ArrayList говорит, что два элемента не равны, то HashMap также не сможет. Это означает, что ваше второе решение не работает.
Я рекомендую проверить, действительно ли вы корректно переопределяете equals () и hashCode () и что их подписи совпадают с сигнатурами в классе Object.