equals()와 hashCode()
Coddy Java 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 87개 중 42번째.
Java에서 객체를 비교할 때, == 연산자는 두 참조가 동일한 메모리 위치를 가리키는지 확인합니다. 객체의 실제 내용을 비교하려면 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);
}
}equals() 메서드는 표준 패턴을 따릅니다. 먼저 동일한 객체인지 확인하고, 그 다음 타입을 검증하며, 마지막으로 관련 필드들을 비교합니다.
equals()를 오버라이드할 때마다 hashCode()도 반드시 오버라이드해야 합니다. 이것은 Java의 규약입니다. 서로 같은 객체는 반드시 동일한 해시 코드를 가져야 합니다. HashMap 및 HashSet과 같은 해시 기반 컬렉션은 올바르게 작동하기 위해 이 규칙에 의존합니다.
@Override
public int hashCode() {
return Objects.hash(name, age);
}Objects.hash() 유틸리티 메서드는 equals()에서 사용되는 것과 동일한 필드로부터 해시 코드를 생성합니다. 두 개의 Person 객체가 동일한 name과 age를 가지면, 이들은 동일한 것으로 간주되어 동일한 해시 코드를 생성하며, 이를 통해 컬렉션에서의 일관된 동작을 보장합니다.
챌린지
쉬움객체 동등성(equality)을 올바르게 구현하는 학생 기록 시스템을 구축해 보겠습니다. 학생 ID와 이름이 동일하면 메모리상의 동일한 객체인지 여부와 관계없이 두 학생을 동일한 것으로 간주하는 Student 클래스를 만들 것입니다.
코드는 두 개의 파일로 구성됩니다:
Student.java: 세 개의 private 필드인studentId(String),name(String),gpa(double)를 가진 학생 클래스를 생성합니다. 모든 필드를 초기화하는 생성자와 각 필드에 대한 getter 메서드를 포함하세요.두 Student 객체가 동일한
studentId와 동일한name을 가질 때 동일한 것으로 간주되도록equals()메서드를 오버라이드하세요. 표준 패턴을 따르십시오: 동일 참조 확인, null 및 타입 확인 후 관련 필드 비교.equals()에서 사용된 것과 동일한 필드를 사용하여Objects.hash()로hashCode()메서드를 오버라이드하세요. 파일 상단에java.util.Objects를 임포트하는 것을 잊지 마세요.Main.java: 학생 객체들을 비교하여 Student 클래스를 실제로 작동시켜 봅니다. 두 명의 학생을 나타내는 6개의 입력을 받게 됩니다: 첫 번째 학생의 ID, 이름, GPA에 이어서 두 번째 학생의 ID, 이름, GPA가 주어집니다.두 Student 객체를 생성한 후, 세 가지 비교를 수행하고 결과를 출력하세요:
Same reference:를 출력한 뒤 첫 번째 학생이 자기 자신과 같은지 여부를 출력합니다 (항상 true여야 합니다).Content equality:를 출력한 뒤 첫 번째 학생과 두 번째 학생이 같은지 여부를 출력합니다 (구현한 equals 기준).Hash codes match:를 출력한 뒤 두 학생의 해시 코드가 일치하는지 여부를 출력합니다.
6개의 입력을 받게 됩니다: 첫 번째 학생의 ID (String), 첫 번째 학생의 이름 (String), 첫 번째 학생의 GPA (double), 두 번째 학생의 ID (String), 두 번째 학생의 이름 (String), 그리고 두 번째 학생의 GPA (double).
두 학생의 ID와 이름이 일치할 때, equals()가 true를 반환하고 해시 코드도 일치하게 되는 점에 주목하세요. 이것이 여러분이 유지해야 할 규약(contract)입니다!
치트 시트
== 연산자는 두 참조가 동일한 메모리 위치를 가리키는지 확인하며, 객체가 동일한 내용을 가지고 있는지는 확인하지 않습니다.
객체의 내용을 비교하려면 다음 패턴에 따라 equals() 메서드를 오버라이드하세요:
@Override
public boolean equals(Object obj) {
if (this == obj) return true; // 동일한 참조
if (obj == null || getClass() != obj.getClass()) return false; // Null이거나 다른 타입임
Person person = (Person) obj; // 올바른 타입으로 캐스팅
return age == person.age && name.equals(person.name); // 필드 비교
}equals()를 오버라이드할 때마다 hashCode()도 반드시 오버라이드해야 합니다. 이것은 자바의 규약입니다: 동일한 객체는 반드시 동일한 해시 코드를 가져야 합니다.
@Override
public int hashCode() {
return Objects.hash(name, age);
}equals()에서 사용된 것과 동일한 필드로 Objects.hash()를 사용하세요. 이를 통해 HashMap 및 HashSet과 같은 해시 기반 컬렉션이 올바르게 작동하도록 보장할 수 있습니다.
직접 해보기
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 첫 번째 학생의 데이터 읽기
String id1 = scanner.nextLine();
String name1 = scanner.nextLine();
double gpa1 = scanner.nextDouble();
scanner.nextLine(); // 줄바꿈 문자 소비
// 두 번째 학생의 데이터 읽기
String id2 = scanner.nextLine();
String name2 = scanner.nextLine();
double gpa2 = scanner.nextDouble();
// TODO: 입력 데이터를 사용하여 두 개의 Student 객체 생성
// TODO: "Same reference: "를 출력하고 이어서 student1이 자기 자신과 같은지 여부를 출력
// TODO: "Content equality: "를 출력하고 이어서 student1과 student2가 같은지 여부를 출력
// TODO: "Hash codes match: "를 출력하고 이어서 두 학생이 동일한 해시 코드를 가졌는지 여부를 출력
}
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
4상속
상속의 기초 (extends)super 키워드메서드 오버라이딩 (@Override)생성자 체이닝Object 클래스단일 및 다중 레벨 상속다중 클래스 상속이 불가능한 이유요약 - 직원 계층 구조7특별한 메서드와 Object 클래스
toString() 메서드equals()와 hashCode()clone() 메서드compareTo()와 ComparableComparator 인터페이스요약 - 커스텀 정렬