[Java 개념노트 37] Object 클래스 이해하기
안녕하세요. Java 개념노트 시리즈 서른일곱 번째 글입니다.
지난 글에서는 추상 클래스와 인터페이스의 공통점과 차이점을 비교했습니다. 이번 글에서는 자바의 모든 클래스가 공통으로 가지는 최상위 부모 클래스인 Object 클래스에 대해 알아보겠습니다.
자바를 공부하다 보면 toString(), equals(), hashCode(), getClass() 같은 메서드를 자주 만나게 됩니다. 이 메서드들은 모두 Object 클래스와 관련이 있습니다.
1. Object 클래스란?
Object 클래스는 자바의 모든 클래스가 자동으로 상속받는 최상위 부모 클래스입니다.
우리가 직접 만든 Member, Product, Student 같은 클래스도 결국 Object 클래스를 상속받습니다. 그래서 모든 객체는 Object 클래스가 가진 기본 메서드를 사용할 수 있습니다.
쉽게 말하면
Object 클래스는 자바의 모든 클래스가 공통으로 물려받는 가장 위에 있는 부모 클래스입니다.
2. 모든 클래스는 Object를 상속받는다
아래와 같이 아무것도 상속받지 않은 클래스가 있다고 해보겠습니다.
class Member {
String name;
}
이 클래스는 겉으로 보기에는 아무 클래스도 상속받지 않은 것처럼 보입니다. 하지만 자바에서는 내부적으로 다음과 비슷하게 볼 수 있습니다.
즉, 우리가 extends Object를 직접 쓰지 않아도 자바의 모든 클래스는 Object 클래스를 상속받습니다.
3. Object 클래스가 중요한 이유
Object 클래스가 중요한 이유는 모든 객체가 공통으로 사용할 수 있는 기본 메서드를 제공하기 때문입니다.
| 메서드 | 역할 |
toString() |
객체를 문자열로 표현합니다. |
equals() |
두 객체가 같은지 비교합니다. |
hashCode() |
객체의 해시 값을 반환합니다. |
getClass() |
객체의 클래스 정보를 반환합니다. |
이 메서드들은 앞으로 문자열, 컬렉션, 객체 비교를 배울 때 계속 등장합니다.
4. Object 타입 변수
모든 클래스는 Object를 상속받기 때문에, Object 타입 변수는 어떤 객체든 참조할 수 있습니다.
public class Main {
public static void main(String[] args) {
Object obj1 = new Member();
Object obj2 = new Product();
Object obj3 = "Java";
System.out.println(obj1);
System.out.println(obj2);
System.out.println(obj3);
}
}
class Member {
}
class Product {
}
Member, Product, String 모두 Object의 자식이기 때문에 Object 타입 변수에 저장할 수 있습니다.
핵심 포인트
Object는 모든 클래스의 부모이므로 Object 타입 변수는 다양한 객체를 담을 수 있습니다.
5. toString() 메서드
toString()은 객체를 문자열로 표현할 때 사용하는 메서드입니다.
객체를 출력하면 자바는 내부적으로 toString()을 호출합니다.
public class Main {
public static void main(String[] args) {
Member member = new Member();
System.out.println(member);
System.out.println(member.toString());
}
}
class Member {
}
실행 결과는 다음과 비슷하게 나올 수 있습니다.
Member@1a2b3c4d
Member@1a2b3c4d
출력 결과는 실행 환경마다 다를 수 있습니다. 기본 toString()은 보통 클래스이름@해시값 형태의 문자열을 반환합니다.
6. toString()을 오버라이딩하는 이유
기본 toString() 출력은 사람이 보기 어렵습니다. 그래서 객체 정보를 보기 좋게 출력하고 싶을 때 toString()을 오버라이딩합니다.
public class Main {
public static void main(String[] args) {
Member member = new Member("건", 20);
System.out.println(member);
}
}
class Member {
String name;
int age;
Member(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Member{name='" + name + "', age=" + age + "}";
}
}
실행 결과는 다음과 같습니다.
Member{name='건', age=20}
이제 객체를 출력했을 때 클래스 이름과 의미 없는 값이 아니라, 객체의 필드 정보가 보기 좋게 출력됩니다.
7. equals() 메서드
equals()는 두 객체가 같은지 비교할 때 사용하는 메서드입니다.
하지만 Object 클래스의 기본 equals()는 두 객체의 내용이 아니라 같은 객체인지를 비교합니다.
public class Main {
public static void main(String[] args) {
Member member1 = new Member("user01");
Member member2 = new Member("user01");
System.out.println(member1 == member2);
System.out.println(member1.equals(member2));
}
}
class Member {
String id;
Member(String id) {
this.id = id;
}
}
실행 결과는 다음과 같습니다.
false
false
member1과 member2는 id 값은 같지만 서로 다른 객체입니다. 기본 equals()는 같은 객체인지 비교하기 때문에 false가 나옵니다.
8. == 과 equals()의 차이
==와 equals()는 자주 헷갈립니다.
| 구분 | 비교 기준 | 예시 |
== |
두 참조변수가 같은 객체를 가리키는지 비교 | member1 == member2 |
equals() |
객체가 같은지 비교하는 메서드 | member1.equals(member2) |
기본 상태의 equals()는 ==와 비슷하게 동작합니다. 하지만 equals()를 오버라이딩하면 객체의 내용을 기준으로 비교하도록 바꿀 수 있습니다.
9. equals() 오버라이딩
회원 객체를 비교할 때 id가 같으면 같은 회원으로 보고 싶다고 가정해보겠습니다. 이럴 때 equals()를 오버라이딩할 수 있습니다.
public class Main {
public static void main(String[] args) {
Member member1 = new Member("user01");
Member member2 = new Member("user01");
System.out.println(member1 == member2);
System.out.println(member1.equals(member2));
}
}
class Member {
String id;
Member(String id) {
this.id = id;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Member)) {
return false;
}
Member other = (Member) obj;
return this.id.equals(other.id);
}
}
실행 결과는 다음과 같습니다.
false
true
두 객체는 서로 다른 객체이므로 ==는 false입니다. 하지만 id 값이 같도록 equals()를 오버라이딩했기 때문에 equals()는 true가 나옵니다.
주의
객체의 내용을 기준으로 비교하고 싶다면 equals()를 목적에 맞게 오버라이딩해야 합니다.
10. hashCode() 메서드
hashCode()는 객체의 해시 값을 반환하는 메서드입니다. 해시 값은 객체를 빠르게 찾거나 분류할 때 사용되는 숫자값이라고 생각하면 됩니다.
public class Main {
public static void main(String[] args) {
Member member = new Member("user01");
System.out.println(member.hashCode());
}
}
class Member {
String id;
Member(String id) {
this.id = id;
}
}
실행 결과는 환경마다 다를 수 있습니다.
12345678
숫자는 예시입니다. 실행할 때마다 다르게 보일 수 있습니다.
11. equals()와 hashCode()의 관계
객체 비교에서 중요한 규칙이 있습니다.
equals() 결과가 true인 두 객체는 hashCode() 값도 같아야 합니다.
그래서 equals()를 오버라이딩할 때는 보통 hashCode()도 함께 오버라이딩합니다.
class Member {
String id;
Member(String id) {
this.id = id;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Member)) {
return false;
}
Member other = (Member) obj;
return this.id.equals(other.id);
}
@Override
public int hashCode() {
return id.hashCode();
}
}
위 코드에서는 id가 같으면 같은 객체로 판단하도록 equals()를 만들었고, hashCode()도 id를 기준으로 만들었습니다.
12. getClass() 메서드
getClass()는 객체의 클래스 정보를 가져오는 메서드입니다.
public class Main {
public static void main(String[] args) {
Member member = new Member();
System.out.println(member.getClass());
System.out.println(member.getClass().getName());
System.out.println(member.getClass().getSimpleName());
}
}
class Member {
}
실행 결과는 다음과 비슷합니다.
class Member
Member
Member
패키지가 있는 클래스라면 getName()은 패키지 이름까지 포함한 전체 이름을 반환하고, getSimpleName()은 클래스 이름만 반환합니다.
13. Object 타입 배열
Object 타입 배열에는 여러 종류의 객체를 함께 넣을 수 있습니다.
public class Main {
public static void main(String[] args) {
Object[] values = {
"Java",
100,
3.14,
new Member("건")
};
for (int i = 0; i < values.length; i++) {
System.out.println(values[i]);
}
}
}
class Member {
String name;
Member(String name) {
this.name = name;
}
@Override
public String toString() {
return "Member{name='" + name + "'}";
}
}
실행 결과는 다음과 같습니다.
Java
100
3.14
Member{name='건'}
Object 배열은 다양한 값을 담을 수 있지만, 꺼내서 사용할 때는 실제 타입을 확인해야 하는 경우가 많습니다.
14. Object 타입의 한계
Object 타입 변수는 어떤 객체든 담을 수 있다는 장점이 있지만, Object 타입으로는 Object가 아는 메서드만 바로 호출할 수 있습니다.
Object obj = new Member("건");
System.out.println(obj.toString());
// obj.printName(); // 오류 발생
실제 객체는 Member이지만 변수 타입은 Object입니다. 따라서 Member만 가진 메서드는 바로 호출할 수 없습니다.
필요하다면 instanceof로 타입을 확인하고 다운캐스팅해야 합니다.
Object obj = new Member("건");
if (obj instanceof Member) {
Member member = (Member) obj;
member.printName();
}
15. Object 클래스 전체 예제
이번에는 toString(), equals(), hashCode()를 함께 사용하는 예제를 보겠습니다.
public class Main {
public static void main(String[] args) {
Member member1 = new Member("user01", "건");
Member member2 = new Member("user01", "건");
System.out.println(member1);
System.out.println(member2);
System.out.println(member1 == member2);
System.out.println(member1.equals(member2));
System.out.println(member1.hashCode());
System.out.println(member2.hashCode());
}
}
class Member {
String id;
String name;
Member(String id, String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "Member{id='" + id + "', name='" + name + "'}";
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Member)) {
return false;
}
Member other = (Member) obj;
return this.id.equals(other.id);
}
@Override
public int hashCode() {
return id.hashCode();
}
}
실행 결과는 다음과 비슷합니다.
Member{id='user01', name='건'}
Member{id='user01', name='건'}
false
true
111578566
111578566
두 객체는 서로 다른 객체이므로 ==는 false입니다. 하지만 id가 같으면 같은 회원으로 판단하도록 equals()를 오버라이딩했기 때문에 equals()는 true입니다. 또한 같은 id를 기준으로 hashCode()를 만들었기 때문에 해시 값도 같습니다.
16. Object 클래스 사용 시 자주 하는 실수
Object 클래스를 처음 배울 때는 아래와 같은 실수를 자주 합니다.
| 실수 | 문제점 | 해결 방법 |
| 객체를 출력하면 자동으로 예쁘게 나온다고 생각 | 기본 출력은 클래스명@해시값 형태 | toString() 오버라이딩 |
==와 equals()를 혼동 |
참조 비교와 내용 비교를 헷갈림 | 객체 비교 기준을 먼저 정리 |
equals()만 오버라이딩 |
해시 기반 자료구조에서 문제가 생길 수 있음 | hashCode()도 함께 고려 |
| Object 타입으로 자식 고유 메서드 호출 | Object가 모르는 메서드는 호출 불가 | 다운캐스팅 필요 여부 확인 |
equals()에서 타입 확인 누락 |
잘못된 타입 비교 시 오류 가능 | instanceof로 타입 확인 |
17. 직접 연습해보기
아래 코드를 직접 작성하고 실행해보세요.
public class Main {
public static void main(String[] args) {
Product product1 = new Product("P001", "키보드", 50000);
Product product2 = new Product("P001", "기계식 키보드", 60000);
Product product3 = new Product("P002", "마우스", 30000);
System.out.println(product1);
System.out.println(product2);
System.out.println(product3);
System.out.println(product1.equals(product2));
System.out.println(product1.equals(product3));
System.out.println(product1.hashCode());
System.out.println(product2.hashCode());
}
}
class Product {
String code;
String name;
int price;
Product(String code, String name, int price) {
this.code = code;
this.name = name;
this.price = price;
}
@Override
public String toString() {
return "Product{code='" + code + "', name='" + name + "', price=" + price + "}";
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Product)) {
return false;
}
Product other = (Product) obj;
return this.code.equals(other.code);
}
@Override
public int hashCode() {
return code.hashCode();
}
}
실행 결과는 다음과 비슷합니다.
Product{code='P001', name='키보드', price=50000}
Product{code='P001', name='기계식 키보드', price=60000}
Product{code='P002', name='마우스', price=30000}
true
false
2431744
2431744
18. 이번 글 정리
이번 글에서는 자바의 모든 클래스가 상속받는 Object 클래스에 대해 정리했습니다. 핵심 내용은 다음과 같습니다.
- Object 클래스는 자바의 모든 클래스가 상속받는 최상위 부모 클래스이다.
- 클래스가 아무것도 상속받지 않아도 내부적으로 Object를 상속받는다.
- Object 타입 변수는 다양한 객체를 참조할 수 있다.
toString()은 객체를 문자열로 표현하는 메서드이다.- 객체를 보기 좋게 출력하려면
toString()을 오버라이딩할 수 있다. equals()는 두 객체가 같은지 비교하는 메서드이다.- 기본
equals()는 같은 객체인지 비교한다. - 객체의 내용을 기준으로 비교하려면
equals()를 오버라이딩해야 한다. hashCode()는 객체의 해시 값을 반환한다.equals()를 오버라이딩할 때는hashCode()도 함께 고려해야 한다.getClass()는 객체의 클래스 정보를 확인할 때 사용한다.
한 줄 요약
Object 클래스는 모든 자바 클래스의 최상위 부모이며, 객체 출력, 객체 비교, 해시값, 클래스 정보 확인과 관련된 기본 메서드를 제공합니다.
다음 글 예고
다음 글에서는 [Java 개념노트 38] String 클래스 이해하기라는 주제로 문자열을 다루는 대표 클래스와 문자열 비교, 불변 객체 개념을 정리해보겠습니다.
GWDEVELBlog Java 개념노트 시리즈

'Computer Science > Java' 카테고리의 다른 글
| [Java ] 개념노트 39 StringBuilder 이해하기 (0) | 2026.06.14 |
|---|---|
| [Java ] 개념노트 38 String 클래스 이해하기 (0) | 2026.06.14 |
| [Java] 개념노트 36 추상 클래스와 인터페이스 비교하기 (1) | 2026.06.14 |
| [Java ]개념노트 35 인터페이스 이해하기 (0) | 2026.06.13 |
| [Java]개념노트 34 추상 클래스 이해하기 (0) | 2026.06.13 |