1. Comparando objetos en Java
En Java, los objetos se pueden comparar tanto por referencia como por valor.
Comparando referencias
Si dos variables apuntan al mismo objeto en la memoria, entonces las referencias almacenadas en estas variables son iguales. Si compara estas variables usando el operador de igualdad ( ==), obtiene verdadero y ese resultado tiene sentido. Todo es simple aquí.
| Código | Salida de consola |
|---|---|
|
|
Comparando por valor
Pero a menudo puede encontrar situaciones en las que dos variables se refieren a dos objetos distintos que son idénticos. Por ejemplo, dos objetos de cadenas diferentes que contienen el mismo texto.
Para determinar si diferentes objetos son idénticos, utilice el equals()método. Por ejemplo:
| Código | Salida de consola |
|---|---|
|
|
El equalsmétodo no se limita a la Stringclase. Cada clase lo tiene.
Incluso las clases que escribes por tu cuenta, y he aquí por qué.
2. Objectclase
Todas las clases en Java heredan la Objectclase. A los creadores de Java se les ocurrió este enfoque.
Y si una clase hereda la Objectclase, entonces gana todos los métodos de la Objectclase. Y esta es una de las principales consecuencias de la herencia.
En otras palabras, cada clase tiene los métodos de la Objectclase, incluso si su código no los menciona.
Estos métodos heredados incluyen métodos relacionados con la comparación de objetos. Estos son los métodos equals()y hashCode().
| Código | En realidad, esto es lo que tendremos: |
|---|---|
|
|
En el ejemplo anterior, creamos una Personclase simple con parámetros de nombre y edad, pero no un único método. Pero debido a que todas las clases heredan la Objectclase, la Personclase automáticamente tiene dos métodos:
| Método | Descripción |
|---|---|
|
Compara el objeto actual y el objeto pasado |
|
Devuelve el código hash del objeto actual |
Resulta que absolutamente todos los objetos tienen el equalsmétodo, y los objetos de diferentes tipos se pueden comparar entre sí. Dicho código se compilará y funcionará perfectamente.
| Código | Salida de consola |
|---|---|
|
|
|
|
3. equals()método
El equals()método, heredado de la Objectclase, implementa el algoritmo más simple para comparar el objeto actual con los objetos pasados: solo compara las referencias a los objetos.
Obtiene el mismo resultado si solo compara Personvariables en lugar de llamar al equals()método. Ejemplo:
| Código | Salida de consola |
|---|---|
|
|
Cuando equalsse llama al método a, simplemente compara la referencia almacenada en la avariable con la referencia almacenada en la bvariable.
Sin embargo, la comparación funciona de manera diferente para la Stringclase. ¿Por qué?
Porque la gente que creó la Stringclase escribió su propia implementación del equals()método.
Implementación del equals()método
Ahora escribamos nuestra propia implementación del método equals en la Personclase. Consideraremos 4 casos principales.
equalsmétodo, siempre toma un
Objectobjeto como argumento
Escenario 1 : el mismo objeto en el que equalsse llama al método también se pasa al equalsmétodo. Si las referencias del objeto actual y el objeto pasado son iguales, el método debe devolver true. Un objeto es igual a sí mismo.
En código se verá así:
| Código | Descripción |
|---|---|
|
Compara referencias |
Escenario 2 : nullse pasa al equalsmétodo: no tenemos nada con lo que comparar. El objeto en el que equalsse llama al método definitivamente no es nulo, por lo que debemos regresar falseen este caso.
En código se verá así:
| Código | Descripción |
|---|---|
|
Comparar referencias ¿ Es el objeto pasado null? |
Escenario 3 : Personse pasa al equalsmétodo una referencia a un objeto que no es a. ¿ Es el Personobjeto igual al no- Personobjeto? Esa es una pregunta para que el desarrollador de la Personclase decida como él o ella quiera.
Pero, por lo general, los objetos deben ser de la misma clase para ser considerados iguales. Por lo tanto, si se pasa algo que no sea un objeto de la Personclase a nuestro método equals, siempre devolveremos false. ¿Cómo se puede comprobar el tipo de un objeto? Así es, usando el instanceofoperador.
Así es como se ve nuestro nuevo código:
| Código | Descripción |
|---|---|
|
Comparar referencias ¿ Es el objeto pasado null? Si el objeto pasado no es un Person |
4. Comparar dos Personobjetos
¿Con qué terminamos? Si hemos llegado al final del método, entonces tenemos una Personreferencia de objeto que no es null. Entonces lo convertimos a Persony comparamos los datos internos relevantes de ambos objetos. Y ese es nuestro cuarto escenario .
| Código | Descripción |
|---|---|
|
Comparar referencias ¿ Es el objeto pasado null? Si el objeto pasado no es un Person Typecasting |
¿Y cómo comparas dos Personobjetos? Son iguales si tienen el mismo nombre ( name) y edad ( age). El código final se verá así:
| Código | Descripción |
|---|---|
|
Comparar referencias ¿ Es el objeto pasado null? Si el objeto pasado no es un Person Typecasting |
Pero eso no es todo.
Primero, el campo de nombre es un String, por lo que debe comparar el campo de nombre llamando al equalsmétodo.
this.name.equals(person.name)
En segundo lugar, el namecampo puede ser null: en ese caso, no puede llamarlo equals. Necesita un cheque adicional para null:
this.name != null && this.name.equals(person.name)
Dicho esto, si el campo de nombre está nullen ambos Personobjetos, los nombres siguen siendo iguales.
El código para el cuarto escenario podría verse así:
|
Si las edades no son iguales, inmediatamente return false Si this.namees igual a null, no tiene sentido comparar usando el equalsmétodo. Aquí el segundo namecampo es igual a null, o no lo es. Compare los dos campos de nombre usando el equalsmétodo. |
5. hashCode()método
Además del equalsmétodo, que pretende realizar una comparación detallada de todos los campos de ambos objetos, existe otro método que puede utilizarse para una comparación imprecisa pero muy rápida: hashCode().
Imagina que estás ordenando alfabéticamente una lista de miles de palabras y necesitas comparar repetidamente pares de palabras. Y las palabras son largas, compuestas de muchas letras. En términos generales, tal comparación llevaría mucho tiempo.
Pero se puede acelerar. Supongamos que tenemos palabras que comienzan con letras diferentes: inmediatamente queda claro que son diferentes. Pero si comienzan con las mismas letras, todavía no podemos decir cuál será el resultado: las palabras pueden resultar iguales o diferentes.
El hashCode()método funciona utilizando un principio similar. Si lo llama en un objeto, devuelve algún número, análogo a la primera letra de una palabra. Este número tiene las siguientes propiedades:
- Los objetos idénticos siempre tienen el mismo código hash
- Diferentes objetos pueden tener el mismo código hash, o sus códigos hash pueden ser diferentes
- Si los objetos tienen códigos hash diferentes, entonces los objetos son definitivamente diferentes
Para hacer esto aún más claro, reformulemos estas propiedades en términos de palabras:
- Las palabras idénticas siempre tienen las mismas primeras letras.
- Diferentes palabras pueden tener las mismas primeras letras, o sus primeras letras pueden ser diferentes
- Si las palabras tienen primeras letras diferentes, entonces las palabras son definitivamente diferentes
La última propiedad se utiliza para acelerar la comparación de objetos:
Primero, se calculan los códigos hash de los dos objetos. Si estos códigos hash son diferentes, entonces los objetos son definitivamente diferentes y no hay necesidad de compararlos más.
Pero si los códigos hash son los mismos, todavía tenemos que comparar los objetos usando el método de igualdad.
6. Contratos en clave
El comportamiento descrito anteriormente debe ser implementado por todas las clases en Java. Durante la compilación, no hay forma de comprobar si los objetos se comparan correctamente.
Los programadores de Java tienen un acuerdo universal de que si escriben su propia implementación del método equals() y, por lo tanto, anulan la implementación estándar (en la Objectclase), también deben escribir su propia implementación del hashCode()método de tal manera que se cumplan las reglas antes mencionadas. satisfecho.
Este arreglo se llama contrato .
Si implementa solo el equals()o solo el hashCode()método en su clase, entonces está violando gravemente el contrato (ha roto el acuerdo). No hagas esto.
Si otros programadores usan su código, es posible que no funcione correctamente. Además, utilizará un código que se basa en el cumplimiento de los contratos anteriores.
Al buscar un elemento, todas las colecciones de Java primero comparan los códigos hash de los objetos y solo luego realizan una comparación utilizando el equalsmétodo.
Eso significa que si le da a su propia clase un equalsmétodo pero no escribe su propio hashCode()método o lo implementa incorrectamente, es posible que las colecciones no funcionen correctamente con sus objetos.
Por ejemplo, puede agregar un objeto a una lista y luego buscarlo usando el contains()método, pero es posible que la colección no encuentre su objeto.
GO TO FULL VERSION