1. Comparando objetos em Java
Em Java, os objetos podem ser comparados tanto por referência quanto por valor.
Comparando referências
Se duas variáveis apontam para o mesmo objeto na memória, então as referências armazenadas nessas variáveis são iguais. Se você comparar essas variáveis usando o operador de igualdade ( ==), obterá true e esse resultado fará sentido. Tudo é simples aqui.
| Código | Saída do console |
|---|---|
|
|
Comparando por valor
Mas muitas vezes você pode encontrar situações em que duas variáveis se referem a dois objetos distintos que são idênticos. Por exemplo, dois objetos strings diferentes que contêm o mesmo texto.
Para determinar se objetos diferentes são idênticos, use o equals()método. Por exemplo:
| Código | Saída do console |
|---|---|
|
|
O equalsmétodo não está limitado à Stringclasse. Toda aula tem.
Mesmo aulas que você escreve por conta própria, e aqui está o porquê.
2. Objectclasse
Todas as classes em Java herdam a Objectclasse. Os criadores do Java criaram essa abordagem.
E se uma classe herda a Objectclasse, ela ganha todos os métodos da Objectclasse. E esta é uma das principais consequências da herança.
Em outras palavras, toda classe tem os métodos da Objectclasse, mesmo que seu código não os mencione.
Esses métodos herdados incluem métodos relacionados à comparação de objetos. Estes são os métodos equals()e hashCode().
| Código | Na realidade, eis o que teremos: |
|---|---|
|
|
No exemplo acima, criamos uma Personclasse simples com os parâmetros name e age, mas não um único método. Mas como todas as classes herdam a Objectclasse, a Personclasse possui automaticamente dois métodos:
| Método | Descrição |
|---|---|
|
Compara o objeto atual e o objeto passado |
|
Retorna o hashcode do objeto atual |
Acontece que absolutamente todo objeto tem o equalsmétodo e objetos de diferentes tipos podem ser comparados entre si. Esse código irá compilar e funcionar perfeitamente.
| Código | Saída do console |
|---|---|
|
|
|
|
3. equals()método
O equals()método, herdado da Objectclasse, implementa o algoritmo mais simples para comparar o objeto atual com os objetos passados: ele apenas compara as referências aos objetos.
Você obtém o mesmo resultado se apenas comparar Personvariáveis em vez de chamar o equals()método. Exemplo:
| Código | Saída do console |
|---|---|
|
|
Quando o equalsmétodo é chamado a, ele simplesmente compara a referência armazenada na avariável com a referência armazenada na bvariável.
No entanto, a comparação funciona de maneira diferente para a Stringclasse. Por que?
Porque o pessoal que criou a Stringclasse escreveu sua própria implementação do equals()método.
Implementação do equals()método
Agora vamos escrever nossa própria implementação do método equals na Personclasse. Vamos considerar 4 casos principais.
equalsmétodo, sempre leva um
Objectobjeto como argumento
Cenário 1 : o mesmo objeto no qual o equalsmétodo é chamado também é passado para o equalsmétodo. Se as referências do objeto atual e do objeto passado forem iguais, o método deve retornar true. Um objeto é igual a si mesmo.
No código ficará assim:
| Código | Descrição |
|---|---|
|
Comparar referências |
Cenário 2 : nullé passado para o equalsmétodo — não temos nada para comparar. O objeto no qual o equalsmétodo é chamado definitivamente não é nulo, então precisamos retornar falseneste caso.
No código ficará assim:
| Código | Descrição |
|---|---|
|
Compare referências É o objeto passado null? |
Cenário 3 : uma referência a um objeto que não é a Personé passada para o equalsmétodo. O Personobjeto é igual ao não- Personobjeto? Essa é uma questão para o desenvolvedor da Personclasse decidir como quiser.
Mas geralmente os objetos devem ser da mesma classe para serem considerados iguais. Portanto, se algo diferente de um objeto da Personclasse for passado para o nosso método equals, sempre retornaremos false. Como você pode verificar o tipo de um objeto? Isso mesmo — usando o instanceofoperador.
Aqui está a aparência do nosso novo código:
| Código | Descrição |
|---|---|
|
Compare referências É o objeto passado null? Se o objeto passado não for um Person |
4. Comparando dois Personobjetos
Com o que terminamos? Se chegamos ao fim do método, então temos uma Personreferência de objeto que não é null. Portanto, convertemos em a Persone comparamos os dados internos relevantes de ambos os objetos. E esse é o nosso quarto cenário .
| Código | Descrição |
|---|---|
|
Compare referências É o objeto passado null? Se o objeto passado não for um Person Typecasting |
E como você compara dois Personobjetos? São iguais se tiverem o mesmo nome ( name) e idade ( age). O código final ficará assim:
| Código | Descrição |
|---|---|
|
Compare referências É o objeto passado null? Se o objeto passado não for um Person Typecasting |
Mas isso não é tudo.
Primeiro, o campo de nome é um String, então você precisa comparar o campo de nome chamando o equalsmétodo.
this.name.equals(person.name)
Em segundo lugar, o namecampo pode ser null: nesse caso, você não pode invocá equals-lo. Você precisa de uma verificação adicional para null:
this.name != null && this.name.equals(person.name)
Dito isso, se o campo de nome estiver nullem ambos Personos objetos, os nomes ainda serão iguais.
O código para o quarto cenário pode ser assim:
|
Se as idades não forem iguais, imediatamente return false Se this.namefor igual a null, não adianta comparar pelo equalsmétodo. Aqui, o segundo namecampo é igual a null, ou não é. Compare os dois campos de nome usando o equalsmétodo. |
5. hashCode()método
Além do equalsmétodo, que se destina a realizar uma comparação detalhada de todos os campos de ambos os objetos, existe outro método que pode ser utilizado para uma comparação imprecisa, mas muito rápida: hashCode().
Imagine que você está classificando alfabeticamente uma lista de milhares de palavras e precisa comparar pares de palavras repetidamente. E as palavras são longas, compostas por muitas letras. De um modo geral, essa comparação levaria muito tempo.
Mas pode ser acelerado. Suponha que temos palavras que começam com letras diferentes - fica imediatamente claro que são diferentes. Mas se eles começam com as mesmas letras, ainda não podemos dizer qual será o resultado: as palavras podem ser iguais ou diferentes.
O hashCode()método funciona usando um princípio semelhante. Se você chamá-lo em um objeto, ele retornará algum número — análogo à primeira letra de uma palavra. Este número tem as seguintes propriedades:
- Objetos idênticos sempre têm o mesmo hashcode
- Diferentes objetos podem ter o mesmo hashcode ou seus hashcodes podem ser diferentes
- Se os objetos tiverem hashcodes diferentes, então os objetos são definitivamente diferentes
Para tornar isso ainda mais claro, vamos reformular essas propriedades em termos de palavras:
- Palavras idênticas sempre têm as mesmas primeiras letras.
- Palavras diferentes podem ter as mesmas primeiras letras ou suas primeiras letras podem ser diferentes
- Se as palavras tiverem primeiras letras diferentes, então as palavras são definitivamente diferentes
A última propriedade é usada para acelerar a comparação de objetos:
Primeiro, os hashcodes dos dois objetos são calculados. Se esses hashcodes forem diferentes, os objetos são definitivamente diferentes e não há necessidade de compará-los mais.
Mas se os hashcodes forem os mesmos, ainda teremos que comparar os objetos usando o método equals.
6. Contratos em código
O comportamento descrito acima deve ser implementado por todas as classes em Java. Durante a compilação, não há como verificar se os objetos são comparados corretamente.
Os programadores Java têm um acordo universal de que, se escreverem sua própria implementação do método equals() e, assim, substituir a implementação padrão (na Objectclasse), eles também devem escrever sua própria implementação do hashCode()método de forma que as regras mencionadas sejam satisfeito.
Esse arranjo é chamado de contrato .
Se você implementar apenas o equals()ou apenas o hashCode()método em sua classe, estará violando grosseiramente o contrato (você quebrou o acordo). Não faça isso.
Se outros programadores usarem seu código, ele pode não funcionar corretamente. Além do mais, você usará um código que depende da adesão aos contratos acima.
Ao pesquisar um elemento, todas as coleções Java primeiro comparam os hashcodes dos objetos e só então realizam uma comparação usando o equalsmétodo.
Isso significa que, se você fornecer um equalsmétodo para sua própria classe, mas não escrever seu próprio hashCode()método ou implementá-lo incorretamente, as coleções podem não funcionar corretamente com seus objetos.
Por exemplo, você pode adicionar um objeto a uma lista e procurá-lo usando o contains()método, mas a coleção pode não localizar seu objeto.
GO TO FULL VERSION