[Resolvido]HashMap Chaves Duplicadas

Estou estudando as Collections e surgiu uma dúvida com relação a HashMap, não é possível de forma alguma ter chaves duplicadas, sendo assim fiquei em dúvida em porque/como o método equals funciona neste caso, com base no que já falei o equals servirá para comparar dois objetos de acordo com o atributo que eu especificar, porém a saída do código que eu testei ficou estranha, vejam:

package projetoparateste;

import java.util.*;

class Dog {
	String name;
	public Dog (String n) {this.name = n;}

	@Override
	public boolean equals(Object o){
		if ((o instanceof Dog) && (((Dog)o).name == this.name)) {
			return true;
		} else {
			return false;
		}
	}
	@Override
	public int hashCode(){
		return this.name.length();
	}
}

public class ProjetoParaTeste {
    public static void main(String[] args) {
		Map<Object, Object> mapa = new HashMap<Object, Object>();
		Dog dg = new Dog("cao");
		Dog dg1 = new Dog("cao");

		mapa.put(dg, "afonso");
		mapa.put(dg1, "jose");

		System.out.println(mapa.get(dg));
		System.out.println(mapa.get(dg1));
    }
}

Retorna: Jose, Jose.
Não deveria dar erro quando tento usar uma chave “duplicada”?

Oi gRoOve,

Não da erro quando vc adiciona uma chave que já existe, o método put vai atualizar o valor da chave com o novo valor associado. Por isso que quando vc passou a mesma chave ele retornou o ultimo nome que você adicionou.

http://download.oracle.com/javase/6/docs/api/java/util/HashMap.html#put(K,%20V)

Outro detalhe: A única regra do hashCode é que objetos iguais devem ter hashes iguais. Porém, a regra não diz nada sobre objetos diferentes.

Como é possível que objetos diferentes tenham hashes iguais, existe um tratamento para quando há colisão de hashCodes. Esse tratamento, envolve testar a chave em questão através do equals.
O HashMap só negará a duplicata caso, além do hash igual, o equals também indique que se trata mesmo de um objeto idêntico.

No seu caso, é possível simular chamando um objeto de “dog” e outro de “cao”. Note que ambos retornarão o mesmo hash (pois o nome tem exatamente o mesmo número de caracteres), mas não se referem ao mesmo cachorro (o equals será false nesse caso).

Entendi. Só fiquei com mais uma dúvida neste trecho do código:

((Dog)o).name == this.name))

Neste caso a string name do objeto atual está sendo comparada com a string name do objeto que está sendo passado, contudo está fazendo a comparação usando “==”, neste caso não estaria comparando a referência na memória e não o valor?

Outra coisa, neste caso os métodos equals e hashcode são chamados quando? Sempre que a classe for instanciada?

Sim, isso está errado mesmo. Como as Strings desse exemplo são todas literais (declaradas com “”) não haverá problemas. Mas na prática, não se pode comprar Strings assim, tem que ser com equals.

O hashCode vai ser chamado pelo hashMap sempre que tiver que buscar por um objeto. Isso é, em funções como put, contains, remove, etc…
O equals é chamado, nesse caso, caso o método encontre alguém com o hash lá.

Vlw Vini, esclareceu minhas dúvidas :slight_smile:
Só faltou uma, quando ocorrer de ter dois objetos iguais como meu exemplo, funcionam como referências na memória? Tipo, se estão “apontando” pro mesmo objeto, independente de qual eu alterar vão alterar os dois?

Quando vc compara com == o java simplesmente testa se as duas variáveis apontam para o mesmo endereço de memória.
Se os dados estão no mesmo endereço, então é um dado só, com dois “apelidos”, não dois. Logo, se alterar o dado, os dois “apelidos” verão a alteração.

OK. Obrigado pelas explicações, foram de grande ajuda :slight_smile: