[Java] Object 클래스(equals / hashCode / toString / 스레드)
by 우와한개발자
1. Object 클래스란?
- Object 클래스는 자바의 모든 클래스의 최상위(root) 클래스
- 클래스를 선언할 때 extends를 명시하지 않으면, 컴파일러가 자동으로 extends Object를 삽입
- 즉, 자바의 모든 클래스는 직접 또는 간접적으로 Object 클래스를 상속 받음
// 아래 두 선언은 동일
public class Person { ... }
public class Person extends Object { ... }
2. Object 클래스의 주요 메서드
| 메서드 | 반환 타입 | 설명 |
| equals(Object obj) | boolean | 두 객체의 내용(값) 이 같은지 비교. 재정의 필요 |
| hashCode() | int | 객체의 해시코드 값 반환. equals()와 함께 재정의 필요 |
| toString() | String | 객체를 문자열로 반환. 재정의하지 않으면 클래스명@해시코드 출력 |
| clone() | Object | 객체를 복제하여 반환 (Cloneable 구현 필요, protected) |
| wait() | void | 현재 스레드를 대기 상태로 전환 (final) |
| wait(long timeout) | void | 지정 시간(ms) 동안 대기 (final) |
| wait(long timeout, int nanos) | void | 지정 시간(ms+ns) 동안 대기 (final) |
| notify() | void | 대기 중인 스레드 하나를 깨움 (final) |
| notifyAll() | void | 대기 중인 모든 스레드를 깨움 (final) |
| finalize() | void | GC가 객체를 메모리에서 제거하기 직전에 호출 (protected) |
⚠️ wait(), notify(), notifyAll()은 final이라 재정의(Override) 불가하고 나머지 메서드는 모두 재정의 가능
1) 객체 동등 비교: == vs equals()
- == 연산자 객체 변수끼리 비교할 때 주소(참조값) 를 비교(내용이 같아도 서로 다른 객체이면 false)
- 값(내용) 을 비교하려면 equals() 메서드를 사용
String s1 = "Hello";
String s2 = "Hello";
String s3 = new String("Hello");
String s4 = new String("Hello");
System.out.println(s1 == s2); // true (같은 주소 참조)
System.out.println(s1 == s3); // false (다른 객체)
System.out.println(s3 == s4); // false (다른 객체)
System.out.println(s1.equals(s2)); // true (값 비교)
System.out.println(s1.equals(s3)); // true (값 비교)
System.out.println(s3.equals(s4)); // true (값 비교)
2) equals()와 hashCode() 재정의
- 직접 만든 클래스에서 객체 동등 비교를 하려면 equals() 메서드를 재정의해야 함.
- 그런데 equals()만 재정의하면 HashSet, HashMap 같은 해시 기반 자료구조에서 문제 발생하기 때문에 equals()와 hashCode() 를 둘다 재정의 해야함.
// 해시 기반 자료구조에서의 동등 비교 순서
hashCode() 값 비교
→ 다르면 → 다른 객체 (equals() 호출 안 함)
→ 같으면 → equals() 로 최종 비교 (true면 같은 객체 / false면 다른 객체)
3) toString()
- Object의 기본 toString()은 클래스명@해시코드(16진수) 형태를 반환
- 의미 있는 정보를 출력하려면 재정의해야함
⚠️ String, Integer, Date 같은 Java API 클래스는 toString()이 이미 재정의되어 있어서 값이 바로 출력
3. 스레드 생명주기와 관련된 Object 메서드

1) wait() / notify() / notifyAll()
- wait(), notify(), notifyAll()은 스레드 간 통신을 위한 메서드
- synchronized 블록 안에서만 사용 가능
- final이라 재정의 불가
⚠️ synchronized와의 관계
- synchronized 키워드를 붙이면 해당 스레드가 lock flag 를 가지고 Runnable ↔ Running 상태를 오가며 처리하는 동안 다른 스레드가 끼어들지 못함. 이때 lock을 기다리는 스레드들이Lock Pool에서 대기하게 됨.
// synchronized 없는 버전 (문제 발생) public void push(int i) { stack.add(i); // t1이 여기까지 실행 후 i++; // t2가 끼어들면 stackpoint가 꼬여 데이터 깨짐! } // synchronized 적용 (해결) public synchronized void push(int i) { stack.add(i); i++; }
메서드 이동하는 상태 설명 wait() Running → Wait Pool 락을 반납하고 무한 대기 notify() Wait Pool → Lock Pool 대기 스레드 1개를 깨워 lock 경쟁 참여 notifyAll() Wait Pool → Lock Pool 대기 중인 모든 스레드를 깨워 lock 경쟁 참여
2) finalize()
- GC(Garbage Collector)가 객체를 메모리에서 제거하기 직전에 자동 호출되는 메서드
- 파일, 네트워크 연결 등 자원 해제 용도로 재정의해서 사용 가능
- protected라 직접 호출보다는 GC에 의해 자동 호출됨
@Override
protected void finalize() throws Throwable {
// 객체 소멸 직전에 처리할 작업 (자원 해제 등)
System.out.println("객체 소멸 직전 호출");
}
⚠️ finalize()는 GC가 언제 실행될지 보장이 없기 때문에 자원 해제를 finalize()에만 의존하는 것은 위험함.
- 명시적으로 자원을 해제하는 별도 메서드(예: close())를 따로 두는 것이 권장됨.
- GC를 강제로 빨리 실행시키고 싶을 때 System.gc()를 호출할 수 있지만, 이 역시 즉시 실행을 보장하지 않고 성능 저하를 유발할 수 있어 사용을 권장하지 않음.
'언어 > Java' 카테고리의 다른 글
| [Java] 형식화클래스(DecimalFormat, SimpleDateFormat, MessageFormat, ChoiceFormat) (0) | 2026.03.05 |
|---|---|
| [Java] 날짜 클래스(Date, Calendar)와 지역과 시간대 클래스(Locale, Timezone) (0) | 2026.03.05 |
| [Java] 정규 표현식(regular expression)과 Pattern/Matcher 클래스 (0) | 2026.03.04 |
| [Java] 문자열 클래스(String, StringBuffer, StringBuilder) (0) | 2026.03.04 |
| [Java] 파일 입출력 - 입출력 스트림과 직렬화(Serialization) (0) | 2026.03.04 |
블로그의 정보
우와한개발자 님의 블로그
우와한개발자