[RESOLVIDO] Utilizando objeto como chave em um Map

8 respostas
R

Boa noite pessoal,

No livro SCJP 6, no capítulo de genéricos e coleções, página 327, é dada as seguintes classes:

public class Dog {

	public String name;
	
	public Dog(String n) {
		this.name = n;
	}
	
	@Override
	public boolean equals(Object obj) {
		if ((obj instanceof Dog) && ((Dog) obj).name == name) {
			return true;
		} else {
			return false;
		}
	}
	
	@Override
	public int hashCode() {
		return name.length();
	}
}
public class Cat {}
import java.util.HashMap;
import java.util.Map;

public class MapTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Map<Object, Object> m = new HashMap<Object, Object>();
		
		Dog d1 = new Dog("clover");
		
		m.put(d1, "Dog key");
		m.put(new Cat(), "Cat key");
		
		System.out.println(m.get(d1));
		System.out.println(m.get(new Cat()));
	}

}

O livro diz que a saída será:
Dog key
null

O que está correto, o que eu não estou entendo é a explicação que o livro dá:
“O ponto importante aqui é que o método get() não conseguiu encontrar o objeto Cat que foi inserido anteriormente…
…Por que foi possível usar uma instancia de Dog como chave, enquanto que usar uma instancia de Cat como chave não teve sucesso?
É fácil ver que Dog substituiu equals() e hashCode(), enquanto que Cat não o fez.”

Pra mim pelo que eu entendi o retorno é null porque são utilizadas duas referencias distintas de Cat, tanto que se alterar o trecho de código de modo a utilizar a mesma referencia de Cat tanto na inserção quanto na busca, o retorno será “Cat key”…

Nesse caso eu não estou entendendo bem ou no livro essa explicação não procede?

Valeu!

8 Respostas

Rafael_Guerreiro

Essa explicação procede…

Faça um teste:

Map&lt;Object, Object&gt; m = new HashMap&lt;Object, Object&gt;();  
          
        Dog d1 = new Dog("clover");  
          
        m.put(d1, "Dog key");  

Cat cat1 = new Cat();
        m.put(cat1, "Cat key"); 
Cat cat2 = new Cat();

System.out.println(d1.hashCode());
System.out.println(cat1.hashCode());
System.out.println(cat2.hashCode());

Os 3 números que serão mostrados vão ser diferentes. O map usa esse número para saber de qual registro você está querendo fazer o get…

x111

RodrigoM91:

O que está correto, o que eu não estou entendo é a explicação que o livro dá:
“O ponto importante aqui é que o método get() não conseguiu encontrar o objeto Cat que foi inserido anteriormente…
…Por que foi possível usar uma instancia de Dog como chave, enquanto que usar uma instancia de Cat como chave não teve sucesso?
É fácil ver que Dog substituiu equals() e hashCode(), enquanto que Cat não o fez.”

Pra mim pelo que eu entendi o retorno é null porque são utilizadas duas referencias distintas de Cat, tanto que se alterar o trecho de código de modo a utilizar a mesma referencia de Cat tanto na inserção quanto na busca, o retorno será “Cat key”…

Nesse caso eu não estou entendendo bem ou no livro essa explicação não procede?
Valeu!


A explicação está correta. O que foi colocado é que se você cria dois objetos cats o hascode e equals serão baseados na referencia desses objetos na memória pois não foi sobrescrito hascode e equals, então ele não encontrará a resposta. Agora se você fizer:

System.out.println(m.get(new Dog(“clover”)));

será retornado “Dog key” pois como a classe sobrescreve hashcode e equals as duas classes são iguais se o nome do cachorro for igual!

A

RodrigoM91:
Boa noite pessoal,

No livro SCJP 6, no capítulo de genéricos e coleções, página 327, é dada as seguintes classes:

public class Dog {

	public String name;
	
	public Dog(String n) {
		this.name = n;
	}
	
	@Override
	public boolean equals(Object obj) {
		if ((obj instanceof Dog) && ((Dog) obj).name == name) {
			return true;
		} else {
			return false;
		}
	}
	
	@Override
	public int hashCode() {
		return name.length();
	}
}
public class Cat {}
import java.util.HashMap;
import java.util.Map;

public class MapTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Map<Object, Object> m = new HashMap<Object, Object>();
		
		Dog d1 = new Dog("clover");
		
		m.put(d1, "Dog key");
		m.put(new Cat(), "Cat key");
		
		System.out.println(m.get(d1));
		System.out.println(m.get(new Cat()));
	}

}

O livro diz que a saída será:
Dog key
null

O que está correto, o que eu não estou entendo é a explicação que o livro dá:
“O ponto importante aqui é que o método get() não conseguiu encontrar o objeto Cat que foi inserido anteriormente…
…Por que foi possível usar uma instancia de Dog como chave, enquanto que usar uma instancia de Cat como chave não teve sucesso?
É fácil ver que Dog substituiu equals() e hashCode(), enquanto que Cat não o fez.”

Pra mim pelo que eu entendi o retorno é null porque são utilizadas duas referencias distintas de Cat, tanto que se alterar o trecho de código de modo a utilizar a mesma referencia de Cat tanto na inserção quanto na busca, o retorno será “Cat key”…

Nesse caso eu não estou entendendo bem ou no livro essa explicação não procede?

Valeu!

Veja bem, se neste exemplo vc sobrescrevesse a classe cat da mesma forma que faz com Dog?
No Dog vc sobrescreve o equals() e o hashcode() . Dentro do equals, que é usado pelo get(m.get(d1)). temos um teste onde ser pergunta se o objeto passado é uma instancia do Dog, então se o cat fosse implementado (com sobrescrita dos metodos equals e hashcode) da mesma forma ele passaria no teste (no if) pois um new cat() é uma instância de cat, ou de outra forma um new cat(“miau”) também passaria no teste pois este objeto é uma instância de cat. Assim de uma maneira geral ele diz que o cat retorna null porque não foi feita a sobrescrita dos métodos equals e hashcode.
Mas vc poderia colocar uma implementação diferente para esses métodos de forma que cada new cat() fosse diferente do outro, claro que respeitando as regras de sobrescritas desses métodos.

R

Boa tarde pessoal,

Entendi o que os três explicaram…!

Eu até posso então usar o objeto Cat como chave no map mais se torna ineficiente já que para recuperar eu teria que ter a mesma instancia do objeto, não é mesmo?

Exemplo:

import java.util.HashMap;
import java.util.Map;

class MapTest {
	public static void main(String[] args) {
		Map<Object, Object> m = new HashMap<Object, Object>();
		
		Cat cat = new Cat();
		
		m.put(cat, "Cat key");
		
		System.out.println(m.get(cat));
}
}

O eficiente seria fazer conforme o livro da o exemplo do Dog que é implementar o método equals() e hashCode(), pra determinar em que situação dois objetos com instancias diferentes serão iguais e seus valores hash que serão usados para busca…

Certo?

Falo!

x111

RodrigoM91:
Boa tarde pessoal,

Entendi o que os três explicaram…!

Eu até posso então usar o objeto Cat como chave no map mais se torna ineficiente já que para recuperar eu teria que ter a mesma instancia do objeto, não é mesmo?

Exemplo:

import java.util.HashMap;
import java.util.Map;

class MapTest {
	public static void main(String[] args) {
		Map<Object, Object> m = new HashMap<Object, Object>();
		
		Cat cat = new Cat();
		
		m.put(cat, "Cat key");
		
		System.out.println(m.get(cat));
}
}

O eficiente seria fazer conforme o livro da o exemplo do Dog que é implementar o método equals() e hashCode(), pra determinar em que situação dois objetos com instancias diferentes serão iguais e seus valores hash que serão usados para busca…

Certo?

Falo!


Eficiente e eneficiente não são as palavras corretas. A busca será tão eficiente no HashMap com a referência ou sem! O que ele quis colocar é a como diferenciar objetos! No caso do cachorro dois objetos são iguais se tiverem o mesmo nome. Porém, como foi implementado, eu posso ter dois cachorros diferentes porém com o mesmo hash, desde que o tenham os nomes tenham os mesmos números de letras!
A questão é que se você utilizar um hashMap ou set, ou qualquer outra forma de coleção com hash terá que implementar hashCode e equals. Na verdade não é correto utilizar um HashMap com objetos que não implementam hashcode equals

A

RodrigoM91:
Boa tarde pessoal,

Entendi o que os três explicaram…!

Eu até posso então usar o objeto Cat como chave no map mais se torna ineficiente já que para recuperar eu teria que ter a mesma instancia do objeto, não é mesmo?

Exemplo:

import java.util.HashMap;
import java.util.Map;

class MapTest {
	public static void main(String[] args) {
		Map<Object, Object> m = new HashMap<Object, Object>();
		
		Cat cat = new Cat();
		
		m.put(cat, "Cat key");
		
		System.out.println(m.get(cat));
}
}

O eficiente seria fazer conforme o livro da o exemplo do Dog que é implementar o método equals() e hashCode(), pra determinar em que situação dois objetos com instancias diferentes serão iguais e seus valores hash que serão usados para busca…

Certo?

Falo!

isso as suas dois questionamentos estão corretos.

A

x@ndy:
RodrigoM91:
Boa tarde pessoal,

Entendi o que os três explicaram…!

Eu até posso então usar o objeto Cat como chave no map mais se torna ineficiente já que para recuperar eu teria que ter a mesma instancia do objeto, não é mesmo?

Exemplo:

import java.util.HashMap;
import java.util.Map;

class MapTest {
	public static void main(String[] args) {
		Map<Object, Object> m = new HashMap<Object, Object>();
		
		Cat cat = new Cat();
		
		m.put(cat, "Cat key");
		
		System.out.println(m.get(cat));
}
}

O eficiente seria fazer conforme o livro da o exemplo do Dog que é implementar o método equals() e hashCode(), pra determinar em que situação dois objetos com instancias diferentes serão iguais e seus valores hash que serão usados para busca…

Certo?

Falo!


Eficiente e eneficiente não são as palavras corretas. A busca será tão eficiente no HashMap com a referência ou sem! O que ele quis colocar é a como diferenciar objetos! No caso do cachorro dois objetos são iguais se tiverem o mesmo nome. Porém, como foi implementado, eu posso ter dois cachorros diferentes porém com o mesmo hash, desde que o tenham os nomes tenham os mesmos números de letras!
A questão é que se você utilizar um hashMap ou set, ou qualquer outra forma de coleção com hash terá que implementar hashCode e equals. Na verdade não é correto utilizar um HashMap com objetos que não implementam hashcode equals

exato , terão o mesmo Hash caso tenham o mesmo tamanho do nome, apesar de não serem o mesmo objeto em relação ao equals que exige que tenham o mesmo nome para serem considerados iguais.

R

Blz Valeu, resolvido!

Criado 22 de março de 2013
Ultima resposta 22 de mar. de 2013
Respostas 8
Participantes 4