Что будет с программой, если hashCode и equals переопределены корректно
Что проверяют
Знаете ли вы контракт equals и hashCode и понимаете ли, что корректная реализация сама по себе ещё ничего не гарантирует. Формулировка вопроса провокационная: ждут не пересказа правил, а того, что вы назовёте оставшееся условие.
Как отвечать
Если контракт соблюдён, хэш-коллекции работают как ожидается: равные объекты попадают в одну корзину, признаются дубликатами в HashSet, находятся ключом в HashMap, схлопываются в distinct. Сам контракт короткий: равные объекты обязаны давать равный хэш, обратное неверно; equals рефлексивен, симметричен, транзитивен, стабилен, и сравнение с null всегда ложно. Считаться оба метода должны по одному и тому же набору полей.
Дальше называйте условие, которого в вопросе нет: объект должен быть неизменяемым по этим полям, пока он лежит в коллекции. Хэш вычисляется в момент вставки, и после изменения поля объект ищется уже в другой корзине, поэтому set.contains(obj) вернёт ложь на том самом объекте, который туда клали.
На Android к этому добавляется практика: в Kotlin data class генерирует оба метода по параметрам первичного конструктора, и поля, объявленные в теле класса, в сравнение не попадают. В Java пишут через Objects.equals и Objects.hash. Для списков это ещё и про DiffUtil, где areContentsTheSame обычно сводится к equals: неверная реализация даёт либо мигание всего списка, либо не обновившиеся строки.
Где спотыкаются
Объявляют метод с параметром своего типа вместо Object. Это перегрузка, а не переопределение: коллекции вызовут версию из Object, и сравнение снова пойдёт по ссылке. Аннотация @Override ловит это на компиляции.
Второе: кладут в хэш изменяемое поле, потом меняют его у объекта внутри множества. Элемент становится недостижимым, но занимает память, а обход коллекции его по-прежнему показывает.
Третье: возвращают константу из hashCode, чтобы контракт точно не нарушился. Формально это законно, но все объекты попадают в одну корзину, и HashMap вырождается в линейный поиск.