Com exceção dos tipos primitivos, TUDO, isso mesmo, TUDO em Java é um objeto. Sendo assim, todos eles derivam da classe Object que, por sua vez, possui métodos que irão passar pra todas as suas classes filhas. Entre estes métodos está o equals(), que será abordado neste artigo.
Sobrescrevendo equals()
O método equals é utilizado para comparações. A classe String e as classes Wrapper sobrescrevem equals() para garantir que dois objetos desses tipos, com o mesmo conteúdo, possam ser considerados iguais. Quando a finalidade for descobrir se duas referências são iguais, o operador “= =” deverá ser usado, pois serão comparados os bits das variáveis.
Existem situações onde não queremos que uma classe seja considerada, em hipótese alguma, idêntica à outra. Por exemplo, existe um laptop X que possui os atributos Y. Assim como existe um laptop Z que também possui os atributos Y. Eles são iguais? Ou melhor, seus donos querem que eles sejam considerados iguais? Que não possuam seu respectivo dono, já que são idênticos?! Em casos como esses será necessários que o método equals() seja sobrescrito a fim de garantirmos que jamais um laptop seja igual a outro.
E se o equals() não for sobrescrito?
Toda comparação com equals() irá verificar, primeiro, se existe uma sobrescrição do mesmo em ambas as classes. Caso não haja em alguma delas, o método padrão da classe Object será utilizado. E, no nosso caso, pode ser que os laptops sejam considerados iguais.
Uma outra limitação que ocorrerá caso o método não seja sobrescrito, é que não será possível utilizar o objeto como chave em uma tabela hashing. Ora, se o método não foi sobrescrito, não será possível encontrar um objeto X na minha tabela! A não ser que eu esteja utilizando o próprio X que foi inserido nela, já que o método equals da classe Object utiliza o comparador “ == “ para verificar se duas referências são iguais. Ou seja, caso tenhamos duas referências diferentes de um mesmo objeto, eles serão considerados diferentes. E isto não pode ocorrer no caso da tabela hash. Nela, queremos encontrar chaves que “batam” com o mesmo tipo de objeto que eu estou procurando. Por exemplo, foi inserido na tabela hashing uma Ferrari vermelha junto com a identificação do seu dono. Agora, preciso recuperar esta Ferrari e seu dono. E agora? E se o método equals só considerar igual uma mesma referência da Ferrari que eu inseri? Caso não se tenha mais uma referência é possível até fazer uma analogia: Como irei mostrar um carro que sirva de exemplo para busca se tudo o que tenho está guardado na garagem?! Ficaria lá, perdido para sempre.
Enfim, caso você precise utilizar objetos em tabelas de hashing (ou qualquer outra estrutua que utilize equivalência para procura - e/ou recuperar - um objeto), terá que sobrescrever equals() para que duas instâncias sejam consideradas iguais. O que poderia ser feito no exemplo anterior era sobrescrever o método equals() a fim de que use o CHASSI do veículo como chave para comparação. Criando um novo carro e setando seu chassi como X, ele irá buscar na tabela um veículo que seja chave e que tenha seu chassi como X. Isto evitará problemas com a segurança do seu projeto.
Implementando um método equals()
Caso queira sobrescrever o método equals em sua classe, ela poderia ficar deste jeito:
Listagem 1: Exemplo de sobrescrição do método equals()
Teríamos como saída:
No exemplo mostrado, a classe Cliente será responsável por cadastrar novos clientes e recuperar clientes antigos de algum lugar, que poderá ser um banco de dados, uma tabela hashing ou qualquer outro mecanismo de comparação. O atributo que foi utilizado para verificar se a classe é igual à outra é o Registro Geral do cliente. A classe Teste estará testando se o mecanismo realmente funciona.
Como estamos tratando de sobrescrição, existem algumas regras a serem seguidas:
Para executar uma sobrescrição válida do método equals, deve-se utilizar a seguinte sintaxe:
public boolean equals(Object o)
{
// Código aqui
}
Sempre deve ser assegurado que estamos tratando do mesmo tipo de objeto. Ou seja, no nosso exemplo, foi verificado se o objeto era do tipo Cliente - utilizando instanceof - e garantimos esta verificação com o &&. Isto assegurará que sempre estaremos lidando com o mesmo tipo de objeto, não correndo o risco de chamar algum método que o objeto recebido não tenha, ou comparar com algo que não exista. Porém, há situações em que os projetistas determinam que dois objetos de classes diferentes são iguais. Isto vai depender de qual projeto você está envolvido.
Segundo a Documentação do Java, o contrato(Regras) de equals() segue as seguintes diretrizes:
- É reflexivo: para qualquer valor de referência x, x.equals() deve retornar true;
- É simétrico: para qualquer valor de referência x e y, x.equals(y) deve retornar true se, e somente se, y.equals(x) retornar true.
- É transitivo: para qualquer valor de referência de x, y e z, se x.equals(y) retornar true e y.equals(z) também retornar true, então, x.equals(z) deve retornar true.
- É consistente: para qualquer valor de referência de x e y, múltiplas chamadas de x.equals(y) retornarão consistentemente true ou consistentemente false, contanto que nenhuma informação usada nas comparações do objeto de equals tenha sido alterada.
- Para qualquer valor de referência x que não seja null, x.equals(null) deve retornar false.
Concluo, assim, este artigo que mostra a praticidade e os benefícios de utilizar a sobrescrição do método equals(). Espero que tenha ajudado no entendimento do assunto e desejo a vocês ótimos estudos!
Abraço!
Referências:
- Bert Bates, Kathy Sierra. Certificação Sun para programadores Java 5 - SCJP(Guia de Estudo)
- http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html