hashCode() duvida

ae pessoal no cap 7 do livro da kathy ela fala que, objetos iguais devem ter o hashing iguais… bom teoricamente ela explicou bem… mais nao explicou a implementação do hashCode() ou seja como cumprir com o contrato… fiquei nessa duvida veja na sintaxe abaixo…

class Has{
	private int n;
	Has(int z){
		n=z;
	}
	public int getInt(){
		return n;
	}
	//subscrevendo para saber se os objetos sao equivalentes
	public boolean equals(Object o){
		if((o instanceof Has)&&(((Has)o).getInt()==this.n)){
			return true;
		}else{
			return false;
		}
	}
		
	
	public static void main(String agrs[]){
		Has h = new Has(9);
		Has h1 = new Has(9);
		System.out.println(h.equals(h1));
	}
}

porem queria saber de os codigos dos objetos sao iguais… implementado o hashCode() mais nem sei por onde ir… quem puder dar esse help :smiley:

Tio, é hashCode ou hasCode? Hein?

Camilo, não sei se entendi a sua duvida, mas quando sobrescrevemos o equals, é seguro sobrescrever o hashcode tbem, para que os mesmos objetos tenham hashcode iguais, para saber o hascode dos objetos basta fazer isso:

objeto.hashcode();

Espero ter ajudado em alguma coisa…

Existem várias formas de se implementar um hashcode. Uma delas, sugerida no livro Effective Java, capítulo 3, item 8, que pode ser lido nesse link (eu recomendo fortemente que você leia o livro todo):
http://java.sun.com/developer/Books/effectivejava/Chapter3.pdf

Ele diz o seguinte:

  1. Armazene algum valor constante, diferente de zero (por exemplo, 17);
  2. Pegue todos os atributos relevantes para sua classe (geralmente são aqueles usados no equals, para saber se o objeto é igual ao outro). Para cada um deles faça, calcule um hashcode inteiro c:
    i. Se o campo é boolean, compute (f ? 0 : 1);
    ii. Se o campo é um byte, char, short ou int, compute (int)f;
    iii. Se o campo é um long, compute (int)(f ^ (f &gt&gt&gt 32));
    iv. Se o campo é um float, compute Float.floatToBits(f);
    v. Se o campo é um double, compute Double.doubleToLongBits(f) e use o hash para longs no resultado descrito no passo iii.
    vi. Se o campo é um objeto, e ele é nulo, compute 0. Caso contrário, use o hashcode desse objeto. Se uma comparação mais profunda é necessária, crie uma "representação canônica" para essa classe, e use o hash dessa representação.
    vii. Se o campo é um array, trate-o como se cada elemento fosse um campo separado.
  3. Combine o hashcode c calculado para cada elemento num resultado como descrito:
    result = 37 * result + c;
  4. Retorne o resultado.

No caso de sua classe, você poderia simplesmente retornar n. Afinal ele é o único atributo e define a igualdade. Entretanto, só para exemplificar, usando o algoritmo descrito acima, teríamos:

public int hashCode() {
  int result = 17;
  result = 37 * result + n; //n é um int, se enquadra na regra ii.
  return result;
}

Supondo que você acrescentasse ainda um outro atributo s, do tipo String, seu código ficaria assim:

public int hashCode() {
  int result = 17;
  result = 37 * result + n; //n é um int, se enquadra na regra ii.
  result = 37 * result + s == null ? 0 : s.hashCode(); //É um objeto, regra vi.
  return result;
}

Esse algoritmo não é o estado da arte de um hashcode, mas é suficientemente rápido, fácil de implementar e bastante confiável.

Por fim, o eclipse gera automaticamente esse algoritmo, para todos os campos de sua classe, se você usar a opção source-&gtgenerate hashcode and equals.

Novamente, dê uma lida no capítulo que eu coloquei o link, para mais considerações e exemplos do uso de hashcode.

Alguns meses depois, postei no GUJ uma classe que implementa esse algorítmo:

ae… galera valeu…mais fiquei na duvida agora veja como ficou meu codigo:

class Has{
	private int n;
	Has(int z){
		n=z;
	}
	public int getInt(){
		return n;
	}
	//subscrevendo para saber se os objetos sao equivalentes
	public boolean equals(Object o){
		if((o instanceof Has)&&(((Has)o).getInt()==this.n)){
			
			return true;
		}else{
			return false;
		}
	}
	
	public static void main(String agrs[]){
		Has h = new Has(9);
		Has h1 = new Has(9);
		System.out.println(h.equals(h1));
		System.out.println(h.hashCode());
		
	}
}

ele imprime o codigo hashinh mais se eu mandar imprimir o h1.hashCode() pq o valor eh diferente ja que os objetos sao equivalentes?

Pela Api,

hashCode() da java.lang.Object é native, e ela dá o valor ‘int’ pegando o endereço do objeto para um int… dois objetos diferentes, dois lugares diferentes da memória…
por isso o hashCode() resulta em valores diferentes… você deveria sobreescrever o “public int hashCode()” para ter o comportamento correto. =]

Camilo, assim como você fez com o equals, você deve sobrescrever o método hashcode. Aliás, o título do capítulo do Effective java que te sugeri já diz tudo: “Sempre sobrescreva o hashCode se você sobrescrever o equals”.

O método hashcode default não tem como adivinhar que você sobrescreveu o equals. E mesmo que tivesse, ele não teria como adivinhar que regra você colocou lá dentro.

No meu post anterior eu te sugeri um algoritmo mais ou menos genérico de como fazer o seu próprio método hashCode, o mesmo usado no Effective Java.

No caso da sua classe, você pode muda-la para:

class Has{
   private int n;
   Has(int z){
      n=z;
   }

   public int getInt(){
      return n;
   }

   //subscrevendo para saber se os objetos sao equivalentes
   public boolean equals(Object o){
      if((o instanceof Has)&&(((Has)o).getInt()==this.n)){
         return true;
      }else{
         return false;
      }
   }

   //sobrescrevendo para garantir o contrato do hash, para o novo equals
   //Estou usando o algoritmo descrito no post anterior, mas nesse caso, 
   //você poderia fazer simplesmente return n.
   public int hashCode() {
      int result = 17;
      result = 37 * result + n; //n é um int, se enquadra na regra ii.
      return result;
   }
 	
   public static void main(String agrs[]){
      Has h = new Has(9);
      Has h1 = new Has(9);
      System.out.println(h.equals(h1));
      System.out.println(h.hashCode() + "=" + h1.hashCode());
   }
}

po galera vaelu entao… conseguir entender… so para resumir… eu posso definir o codigo do meu hashCode() caso venha subscrever ele certo? com as explicacoes de vcs implementei o codigo abaixo:

class Has{
	private int n;
	Has(int z){
		n=z;
	}
	public int getInt(){
		return n;
	}
	//subscrevendo para saber se os objetos sao equivalentes
	public boolean equals(Object o){
		if((o instanceof Has)&&(((Has)o).getInt()==this.n)){
			
			return true;
		}else{
			return false;
		}
	}
	//implementacao do hashCode()
	public int hashCode(){
		return n^17;
	}
	
	public static void main(String agrs[]){
		Has h = new Has(999);
		Has h1 = new Has(999);
		System.out.println(h.equals(h1));
		System.out.println(h.hashCode());
		System.out.println(h1.hashCode());
	}
}
/* implementei meu hashCode quando os objetos sao diferentes eles return o
valor do codigo hashing diferente*/

flw! mesmo… vinny vc anda sumido heim…trabalhando muito pelo visto!!