equals() y hashCode()
Parte de la sección Programación Orientada a Objetos del Journey de Java de Coddy. Lección 42 de 87.
Al comparar objetos en Java, el operador == comprueba si dos referencias apuntan a la misma ubicación de memoria. Para comparar el contenido real de los objetos, debes sobrescribir el método equals().
public class Person {
private String name;
private int age;
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person person = (Person) obj;
return age == person.age && name.equals(person.name);
}
}El método equals() sigue un patrón estándar: primero comprueba si es el mismo objeto, después verifica el tipo y, por último, compara los campos pertinentes.
Siempre que sobrescribas equals(), también debes sobrescribir hashCode(). Este es un contrato de Java: los objetos que son iguales deben tener el mismo código hash. Las colecciones basadas en hash, como HashMap y HashSet, dependen de esta regla para funcionar correctamente.
@Override
public int hashCode() {
return Objects.hash(name, age);
}El método de utilidad Objects.hash() genera un código hash a partir de los mismos campos que se usan en equals(). Si dos objetos Person tienen el mismo nombre y la misma edad, se considerarán iguales y producirán códigos hash idénticos, lo que garantiza un comportamiento coherente en las colecciones.
Desafío
FácilConstruyamos un sistema de registros de estudiantes que implemente correctamente la igualdad entre objetos. Crearás una clase Student en la que dos estudiantes se consideran iguales si tienen el mismo ID de estudiante y el mismo nombre, independientemente de que sean el mismo objeto en memoria.
Organizarás tu código en dos archivos:
Student.java: Crea una clase que represente a un estudiante con tres campos privados:studentId(String),name(String) ygpa(double). Incluye un constructor para inicializar todos los campos y métodos getter para cada campo.Sobrescribe el método
equals()para que dos objetos Student se consideren iguales cuando tengan el mismostudentIdY el mismoname. Sigue el patrón estándar: comprueba si tienen la misma referencia, comprueba si el otro valor es null y su tipo, y luego compara los campos pertinentes.Sobrescribe el método
hashCode()usandoObjects.hash()con los mismos campos utilizados enequals(). Recuerda importarjava.util.Objectsal principio de tu archivo.Main.java: Dale vida a tu clase Student comparando objetos estudiante. Recibirás seis entradas que representan a dos estudiantes: el ID, el nombre y el GPA del primer estudiante, seguidos del ID, el nombre y el GPA del segundo estudiante.Crea ambos objetos Student, después realiza tres comparaciones e imprime los resultados:
- Imprime
Same reference:seguido de si el primer estudiante es igual a sí mismo (debería ser siempre true) - Imprime
Content equality:seguido de si el primer estudiante es igual al segundo (según tu implementación de equals) - Imprime
Hash codes match:seguido de si ambos estudiantes tienen el mismo código hash
- Imprime
Recibirás seis entradas: el ID del primer estudiante (String), el nombre del primer estudiante (String), el GPA del primer estudiante (double), el ID del segundo estudiante (String), el nombre del segundo estudiante (String) y el GPA del segundo estudiante (double).
Observa que cuando dos estudiantes tienen los mismos ID y nombre, tanto equals() devuelve true COMO sus códigos hash coinciden. ¡Este es el contrato que debes mantener!
Pruébalo tú mismo
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Lee los datos del primer estudiante
String id1 = scanner.nextLine();
String name1 = scanner.nextLine();
double gpa1 = scanner.nextDouble();
scanner.nextLine(); // consume el salto de línea
// Lee los datos del segundo estudiante
String id2 = scanner.nextLine();
String name2 = scanner.nextLine();
double gpa2 = scanner.nextDouble();
// TODO: Crea dos objetos Student usando los datos de entrada
// TODO: Imprime "Same reference: " seguido de si student1 es igual a sí mismo
// TODO: Imprime "Content equality: " seguido de si student1 es igual a student2
// TODO: Imprime "Hash codes match: " seguido de si ambos estudiantes tienen el mismo código hash
}
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de OOP
Archivos externosIntroducción a la OOPClases vs. ObjetosLa palabra clave thisMétodosCampos (Atributos)Método constructorSobrecarga de constructoresResumen - Calculadora simple4Herencia
Herencia básica (extends)La palabra clave superSobrescritura de métodos (@Override)Encadenamiento de constructoresLa clase ObjectHerencia simple y multinivelPor qué no hay herencia múltiple de clasesResumen - Jerarquía de empleados7Métodos especiales y la clase Object
Método toString()equals() y hashCode()Método clone()compareTo() y ComparableInterfaz ComparatorResumen - Ordenamiento personalizado2Modificadores de acceso y encapsulamiento
Visión general de los niveles de accesoMétodos Getter y SetterOcultamiento de informaciónLa palabra clave finalResumen - Gestor de cuentas bancarias5Polimorfismo
Fundamentos de sobrecarga de métodosSobrescritura de métodos (tiempo de ejecución)Upcasting y DowncastingEl operador instanceofClases y métodos abstractosResumen - Calculadora de figuras8Conceptos avanzados de POO
Composición vs. HerenciaAgregación vs. ComposiciónClases internas, anidadas y anónimasEnums y métodos de EnumRecords (Java 16+)Clases selladas (Java 17+)11Patrones de diseño - Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón BuilderPatrón ObserverPatrón Strategy3Propiedades de clase y miembros estáticos
Variables de instancia vs. estáticasMétodos estáticosBloques estáticosConstantes (static final)Repaso - Contador y utilidad6Interfaces y Clases Abstractas
Introducción a las InterfacesImplementación de InterfacesImplementación de Múltiples InterfacesMétodos Default y Static en InterfacesClases Abstractas vs InterfacesInterfaces FuncionalesResumen - Sistema de Pagos9Genéricos
Introducción a los genéricosClases genéricasMétodos genéricosParámetros de tipo delimitadosComodines (?, extends, super)Resumen - Contenedor genérico12Patrones de diseño Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositePatrón IteratorPractica por tu cuenta: Compilador de Java online