Java로 개발을 하다 보면 우리가 만든 클래스(Member, Product 등)에서 별도로 정의하지 않은 메소드(toString(), equals() 등)를 자연스럽게 사용하곤 합니다. 이 메소드들은 도대체 어디서 온 걸까요?
바로 Java의 모든 클래스가 묵시적으로 상속받는 최상위 부모, java.lang.Object 클래스 덕분입니다. 이번 포스팅에서는 Java 개발자라면 반드시 알아야 할 Object 클래스의 핵심 기능과, 실무에서 자주 오버라이딩(재정의)해서 사용하는 주요 메소드 3대장(toString, equals, hashCode)에 대해 알아보겠습니다. 👑
## 1. Object 클래스란?
- 정의: 자바의 모든 클래스의 최상위 부모 클래스입니다.
- 특징:
- 우리가 class Member {}라고만 적어도, 컴파일러는 자동으로 class Member extends Object {}라고 처리합니다.
- 따라서 자바의 모든 객체는 Object 클래스에 정의된 메소드를 사용할 수 있습니다.
- 목적: 모든 객체가 공통적으로 가져야 할 필수적인 기능(식별, 문자열 표현 등)을 표준화하기 위함입니다.
## 2. 필수 오버라이딩 메소드 3대장
Object 클래스가 제공하는 11개의 메소드 중, 개발자가 자주 재정의하여 사용하는 가장 중요한 3가지를 살펴보겠습니다.
### 1) toString(): 객체를 문자로 표현하기
- 기본 동작: 클래스명@해시코드(16진수)를 반환합니다. (예: Member@4e50df2e)
- 사용 이유: 객체의 상태(필드 값)를 사람이 읽기 쉬운 문자열로 확인하고 싶을 때 사용합니다. 주로 로그를 찍거나 디버깅할 때 필수적입니다.
[재정의 전]
Member member = new Member("홍길동");
System.out.println(member); // 출력: com.example.Member@4e50df2e (알아보기 힘듦)
[재정의 후]
@Override
public String toString() {
return "Member{name='" + name + "'}";
}
// ...
System.out.println(member); // 출력: Member{name='홍길동'} (명확함!)
### 2) equals(): 객체의 '같음' 비교하기 (중요!)
이 메소드는 기술 면접에서도 단골 질문입니다. **동일성(Identity)**과 **동등성(Equality)**의 차이를 이해해야 합니다.
- 기본 동작 (==): 두 객체의 **주소 값(참조값)**이 같은지 비교합니다. (물리적으로 같은 객체인가?)
- 재정의 목적: 주소 값이 다르더라도, 객체가 가진 내용(값)이 같으면 같은 객체로 취급하기 위함입니다. (논리적으로 같은 객체인가?)
예시: 주민등록번호가 같은 두 사람(Person 객체)이 있다면, 서로 다른 메모리 주소에 생성되었더라도 논리적으로는 '같은 사람'으로 봐야 합니다.
@Override
public boolean equals(Object o) {
if (this == o) return true; // 주소가 같으면 무조건 true
if (o == null || getClass() != o.getClass()) return false; // 타입이 다르면 false
Member member = (Member) o;
// 이름(내용)이 같으면 true 반환
return Objects.equals(name, member.name);
}
### 3) hashCode(): 객체의 지문 (feat. HashMap)
- 기본 동작: 객체의 메모리 주소를 기반으로 생성된 정수 값을 반환합니다.
- 재정의 목적: HashMap이나 HashSet 같은 해시 기반 컬렉션에서 객체를 올바르게 구분하기 위함입니다.
⚠️ 매우 중요한 규칙 (The Contract)
equals()를 재정의했다면, 반드시 hashCode()도 재정의해야 합니다.
논리적으로 같은 객체(equals가 true)라면, 해시코드(hashCode)도 반드시 같아야 하기 때문입니다. 만약 이를 어기면, HashSet에 데이터를 넣었는데 contains()로 찾지 못하는 버그가 발생합니다.
## 3. 그 외의 주요 메소드들
자주 오버라이딩하지는 않지만, 알아두면 좋은 메소드들입니다.
- getClass(): 객체의 클래스 정보(설계도)를 반환합니다. 리플렉션(Reflection) 기술의 시작점이 됩니다.
- clone(): 객체의 복사본을 생성합니다. (하지만 사용이 까다로워 실무에서는 직접 구현하기보다 생성자 복사 등을 권장합니다.)
- wait(), notify(), notifyAll(): 스레드(Thread) 동기화를 위해 사용됩니다. 특정 조건이 충족될 때까지 스레드를 잠시 멈추거나 깨우는 역할을 합니다.
## 4. 요약 정리
| 메소드 | 기본 동작 | 재정의(Override) 목적 |
| toString() | 클래스명@해시코드 반환 | 객체의 정보를 문자열로 쉽게 확인하기 위해 |
| equals() | == (주소 비교) | 객체의 내용(값)이 같은지 비교하기 위해 |
| hashCode() | 주소 기반 정수 반환 | HashMap 등에서 객체를 식별하기 위해 (equals와 짝꿍) |
Object 클래스는 Java의 시작점이자, 모든 객체가 지켜야 할 기본 규칙을 담고 있습니다. 특히 equals와 hashCode는 데이터의 정확성을 위해 반드시 올바르게 재정의해서 사용해야 합니다. (다행히 IntelliJ 같은 IDE나 Lombok 라이브러리가 자동 생성을 도와줍니다!)
'개발 공부 > 자바' 카테고리의 다른 글
| 자바 공부 일지 (기초) (0) | 2026.02.16 |
|---|---|
| 자바 공부 일지 (면접 질문 위주) (0) | 2026.02.16 |
| Java의 다형성 완전 정복 (0) | 2025.09.25 |
| 자바 면접 질문2 (0) | 2025.09.24 |
| 자바 면접 질문1 (0) | 2025.09.24 |