Equals e hashcode sobrescritos

Pessoal, pesquisei muuuito, aqui no guj e no google, mas não consigo entender direito o equals e hashcode sobrescritos, eu entendo usar eles comparando simples objetos, e sei que o hashcode retorna um número que seria uma posição na memória do objeto. Agora pergunto como que isso interfere em coleções, não consigo entender, alguém poderia me dar um exemplo simples de como uma sobrescrita de hashcode e equals que não aderem as regras pode causar problema numa coleção hash. Talvez seja pedir demais, mas serei muito grato se alguém me ajudar.

Por exemplo, suponhamos que para um mesmo objeto, hashcode retorne sempre um valor diferente(por exemplo, se ele retornasse Math.random()).
Nesse caso, se você for inserir esse mesmo objeto repetidas vezes em um HashSet, HashMap, LinkedHashSet, LinkedHashMap ou Hashtable, você teria várias cópias desse mesmo objeto, em vez de ter apenas uma, como esperado. Outro problema é que você nunca iria conseguir encontrá-lo mais no HashSet.

Primeiro vamos esclarecer algumas coisas:

  1. O hashcode não é a posição de memória do objeto. Pelo menos, não em todos os casos. O hashcode é um número que, dado dois objetos diferentes, há baixíssimas chances de ser igual para os dois objetos. E, dado dois objetos iguais, ele é sempre igual. Note que o conceito de hashCode está diretamente relacionado ao conceito de igualdade do seu programa.

  2. Por padrão, o hashcode corresponde ao endereço de memória, pois o Java a comparação padrão do equals é endereços de memória. Agora, se você alterar o equals, terá que alterar também o hashcode. Uma boa forma de se fazer isso está descrita aqui: http://www.guj.com.br/posts/list/52485.java#276120

Agora, como um Set trabalha? Uma estrutura do tipo set poderia ser implementada assim:

private Set<T> {
   private static final int SIZE = 10;
   private T data[] = new T[SIZE];

   public void add(T element) {
        int position = element.hashCode() % SIZE;
        data[position] = element;
   }

   public void contains(T element) {
        int position = element.hashCode() % SIZE;
        return data[position] == element;
   }
}

Repare que nesse Set ultra-simplificado, a posição real do objeto no array é dada pelo HashCode. O java faz algo parecido, embora o Set dele seja muito mais complexo, baseado num map. Esse set ali em cima não trata colisões de hash.

Agora, observe o que o Thingol disse. Suponha que aquele método hashCode() retornasse Random(). O objeto seria cadastrado várias vezes no set! Ou então, suponha que todos os objetos retornassem o mesmo hashCode. Apenas um único objeto ficaria dentro daquele Set!

Agora, mudando de estrutura. Como seria um método contains de um List?

public void contains(T element) { for (T value : elements) { if (value.equals(element)) { return true; } } return false; }

Por isso, é importante que o equals também funcione corretamente para as coleções.

viniiii, me ajuda la no meu topicu!!!

ok entendi, agora é estudar as formas de implementar o hashCode corretamente, apesar do eclipse sobrescrever esse método a um clique do mouse neh?
bom, valeu vini, obrigado mesmo!
Ab.

Quanto a forma, dá uma olhada no link que eu passei ali em cima.

Eu tirei aquela dica do livro Effective Java, que tem um dos melhores capítulos sobre hashcode e equals que já vi.

pois é eu vi…
valeu d+!
Ab.

somente completando o que os colegas falaram acima vou citar dois conjuntos para vc entender a essencia de codigos hashing dentro dos conjuntos.

[quote]HashTable ?(interface Map) essa class não é ordenada, mais segue uma lógica interna para determinar a ordem. Com base nos códigos hashing. Os métodos dessa class são sincronizados.(e pertence a interface MAP). Não aceita nem chaves nem valores null.

LinkedHashSet - mantem a ordem pela inserção e não aceita duplicatas caso o CÓDIGO HASHING esteja implantando de forma correta.

…[/quote]

Integer, Double etc… essas classes possuem o codigo hashing ja implementado, entao quando vc coloca um Integer dentro de um LinkedHashSet ele nao aceita duplicada é porque eles ja tem o codigo hashing implementado… mais se experimente criar um conjunto de uma classe Carro (class Carro) e veja se é possivel inserir dois objetos no LinkedHashSet?
hehe! flw!

valeu pelo complementeo LPJava.
Ab.