Implementação public boolean Equals(Object o)

Amigos,

Qual das duas implementações de equals é melhor (ambas são válidas)?
Peço que justifiquem a escolha.

// Primeira
public boolean equals(Object object)
{
	if ((object instanceof Classe) && ((Classe)object).id == this.id) return true;
	
	return false;
}
// Segunda
public boolean equalsb(Object object)
{
	if ((object != null) && (object.getClass() == this.getClass()) && ((Classe)object).id == this.id) 
                          return true;
	
	return false;
}

Abraços a todos.

a primeira. o primeiro teste de equals sempre deve ser se o objeto passado como paramtro é uma instancia do objeto corrente.
a segunda, sem testar acho que não vai funcionar como o esperado.

[]'s

Na primeira implementação de equals está faltando comparar seu o object != null , para depois
efetuar as outras comparações.

Bom, instanceof já compara com null (null instanceof algumaclasse é sempre false).

Mas a primeira viola o contrato de equals, porque não é simétrica. (Deixo isso como exercício; pense em dois objetos, uma de uma classe X, e outra de uma subclasse Y. )

De modo geral, se você precisa comparar dois objetos com equals, eles têm de pertencer à mesma classe. A segunda já não viola esse contrato.

Uma dica sobre o que o Thingol falou: A primeira seria válida se a classe fosse final.

Além disso, existe o capítulo 3 desse livro é uma ótima referência para quem quer entender direito o equals e o hashCode:
Effective Java

[quote=thingol]Bom, instanceof já compara com null (null instanceof algumaclasse é sempre false).

Mas a primeira viola o contrato de equals, porque não é simétrica. (Deixo isso como exercício; pense em dois objetos, uma de uma classe X, e outra de uma subclasse Y. )

[/quote]

Porquê não é simetrica ?

x.id == y.id <=> y.id == x.id

[quote=lgi2020]Amigos,

// Primeira
public boolean equals(Object object)
{
	if ((object instanceof Classe) && ((Classe)object).id == this.id) return true;
	
	return false;
}

[/quote]

Não precisa usar if

// Primeira
public boolean equals(Object object){
	return (object instanceof Classe) && ((Classe)object).id == this.id);
}

É mesmo sutil. Considere que y é um filho de x.
E que esse filho sobrescreve equals, fazendo a mesma implementação com o instanceof.

Ele pode até mesmo comparar os mesmos atributos.

Nesse caso, quando x.equals(y) será true (já que y instanceof x).
Mas quando y.equals(x) será false (já que x não é uma instância de y).

Mais detalhes link do Effective Java, que deixei ali em cima.

Obrigado pelas respostas e dicas, amigos.

Abraços a todos.

[quote=ViniGodoy]É mesmo sutil. Considere que y é um filho de x.
E que esse filho sobrescreve equals, fazendo a mesma implementação com o instanceof.

Ele pode até mesmo comparar os mesmos atributos.

Nesse caso, quando x.equals(y) será true (já que y instanceof x).
Mas quando y.equals(x) será false (já que x não é uma instância de y).

Mais detalhes link do Effective Java, que deixei ali em cima.[/quote]

Entendi, mas se equals é def na classe pai ( vamos supor que o codigo acima está na classe pai)
seria final e assim:

[code]class A {

public final boolean equals(Object other)
return other instanceof A && ((A)other).id == this.id;
}
[/code]
Se B é filha de A

b = new B(1); // id =1 
a = new A(1);

b.equals(a) == true
a.equals(b) == true

Ou seja “Classe” seria o nome da classe que define o método. Sendo assim dá certo, já que ou (1) A classe pai define equals e é final ou (2) as filhas definem e nesse caso nenhum A é igual a B nunca.
Não ?

Sim, se a classe ou o equals forem final, daí beleza.

Acho que o problema maior é que geralmente não são. E como com o tempo criar um equals se torna um processo mais ou menos automático, o erro acaba sendo introduzido.

O importante é estar atento ao detalhe. Como diz o ditado popular:
“Deus está em todo lugar, mas o diabo está nos detalhes.”