Uma implementação possível do hashSet é um array de listas.
Imagine que cada índice do array são as gavetas de cores, que nosso colega falou. E as listas, é o espaço da gaveta, onde você pode colocar as meias.
Pois bem, se você não implementar o hashCode, o java utilizará a implementação padrão. Essa implementação usa o endereço de memória do objeto para dizer seu hash. Ou seja, dois objetos, usando esse algoritmo, jamais terão o mesmo hashCode. Portanto, é como se todas as suas meias tivessem cores diferentes. Essa é a mesma política adotada para o equals, portanto, esses métodos estão consistentes, mesmo com sua implementação padrão. Ou seja, para a implementação padrão, com objetos diferentes, você nunca precisará testar se uma meia é igual a outra, pois, nessa implementação, você tem exatamente uma gaveta por meia. Você pode fazer com que o método equals seja chamado, basta inserir 2 vezes o mesmo objeto no set.
Quando você implementa o equals, você está alterando a definição de igualdade. Você está dizendo que dois objetos de endereço de memória diferentes podem, eventualmente, ser considerados iguais. Portanto, é necessário também fornecer um hash que indique que eles sejam iguais. O hash é um número, e serve como um atalho para definir se dois objetos são ou não iguais.
Entretanto, o contrário não é verdadeiro. Dois objetos de mesmo hash podem, eventualmente, não serem iguais. O hash é um atalho, o equals é o método que realmente distingue um objeto de outro. Como um HashSet não permite duplicatas, como ele fará para não descartar objetos de mesmo hash que sejam diferentes? É aí que entra a regra que o colega tentou te explicar. Sempre que ele encontra um hash igual, ele irá comparar se o objeto encontrado lá é mesmo igual ao objeto recebido. Se for igual, o objeto será substituido pelo passado. Se for diferente, o objeto será colocado na mesma posição do hashmap, no próximo índice livre da lista.
Um exemplo de caso de hashs iguais são as Strings “auréola” e “desprezível”, como bem citado pelo Thingol. Obseve que a mesma estratégia de combinar hash com equals é também usada no switch do Java 7, como ele explica nesse post: