본문 바로가기
강의 실습/실무 자바 개발을 위한 OOP와 핵심 디자인 패턴

Object 클래스

by jint 2026. 1. 24.

1. 모든 클래스는 Object 클래스의 자손
public class SomeClass {} = public class SomeClass extends Object {}


2. Object 클래스의 주요 메서드
clone(), equals(), finalize(), getClass(), hashCode(), notify(), notifyAll(), toString(), wait()
여기서 중요한 메서드 3가지
-> equals(), hashCode(), toString()

많이 사용되고, 오버라이딩하여 사용해야할 일도 많다.


3. equals()
동일성 vs 동등성

동일성 : 비교 대상이 실제로 '같은' 대상이어야 함 = 둘은 실제로 하나
-> 두 비교 대상을 '==' 연산자로 비교

동등성 : 비교 대상이 같은 값이라고 우리가 정의한 것
-> equals() 메서드를 오버라이딩 하여 비교

동일한 인스턴스는 동등하기도 하다.

- src/main/java/kr/co/programmersoop/example/section_01_07/equals/SomeObject.java

public class SomeObject {
    private int intField;
    private String stringField;

    public SomeObject(int intField, String stringField) {
        this.intField = intField;
        this.stringField = stringField;
    }

    public int getIntField() {
        return intField;
    }

    public String getStringField() {
        return stringField;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        SomeObject that = (SomeObject) o;
        return intField == that.intField && Objects.equals(stringField, that.stringField);
    }
}


위 메서드를 인텔리제이에서 자동으로 생성할 수 있다.

오버라이딩 된 equals(), hashCode() 메서드 생성 방법 : 마우스 우클릭 > 생성 > equals() 및 hashCode() : java.util.Objects.equals...sh() (Java 7 and higher) > equals()에 포함할 필드 선택 intField: int, stringField: String 선택 > hashCode()에 포함할 필드 선택 intField: int, stringField: String 선택 > 생성

@Override
public boolean equals(Object o) {
    // instanceof 식
    // if (!(o instanceof SomeObject that)) return false;
    // getClass() 비교식
    if (o == null || getClass() != o.getClass()) return false;
    SomeObject that = (SomeObject) o;
    return intField == that.intField && Objects.equals(stringField, that.stringField);
}

@Override
public int hashCode() {
    return Objects.hash(intField, stringField);
}


equals 코드가 약간 달라보여도 기능상 완전히 동일하다.

- src/main/java/kr/co/programmersoop/example/section_01_07/equals/EqualsExampleMain.java

public class EqualsExampleMain {
    public static void main(String[] args) {
        SomeObject sameObject1 = new SomeObject(1, "programmers");
        SomeObject sameObject2 = new SomeObject(1, "programmers");
        SomeObject sameObject3 = sameObject1;

        SomeObject anotherObject = new SomeObject(100, "foo");

        // 동일성 비교 -> false
        System.out.println(sameObject1 == sameObject2);

        // 동일성 비교 -> true
        // 같은 인스턴스를 가리키기 때문
        System.out.println(sameObject1 == sameObject3);

        // 동등성 비교 -> true
        System.out.println(sameObject1.equals(sameObject2));

        // 동등성 비교 -> true
        System.out.println(sameObject1.equals(sameObject3));

        // 동등성 비교 -> false
        System.out.println(anotherObject.equals(sameObject1));
    }
}


SomeObject 클래스에서 @Override 메서드를 주석처리 후 다시 비교하면,

- src/main/java/kr/co/programmersoop/example/section_01_07/equals/EqualsExampleMain.java

...
        // 동일성 비교 -> false
        System.out.println(sameObject1 == sameObject2);

        // 동일성 비교 -> true
        System.out.println(sameObject1 == sameObject3);

        // 동등성 비교 -> false
        System.out.println(sameObject1.equals(sameObject2));

        // 동등성 비교 -> true
        System.out.println(sameObject1.equals(sameObject3));

        // 동등성 비교 -> false
        System.out.println(anotherObject.equals(sameObject1));
...


sameObject1와 sameObject2는 같은 필드임에도 불구하고 동등성 비교시 false가 나오는데, equals() 메서드가 정의되어 있지 않아서 어떤 상태에서 동등한지 정의되지 않았기 때문이다.


4. hashCode()

hashCode() 메서드는 언제 어떻게 사용될까?
-> equals() 메서드와 같이 오버라이딩하여, 두 인스턴스가 동등한지 비교
-> hashMap과 같은 해시관련 컬렉션 사용할 때 hashCode() 메서드가 중요하게 사용됨

hashMap은 key를 통해 value를 조회한다. key는 hashCode()한 연산 결과가 key가 된다.
(엄밀히 말하면 hashCode() 값을 capacity(용량)으로 나눈 값의 나머지)

hashCode()한 연산 결과가 겹치는 경우, 2개의 데이터가 조회될 수 있기에 이 때 equals()로 비교한다.
(hashCode()를 작은 수로 나눈 나머지라서 충분히 겹칠 수 있음)

여기서, 처음부터 equals()로 비교하면 될 텐데 왜 hashCode()로 비교할까?
-> 상대적으로 가벼운 hashCode() 연산을 통해 찾으려는 값의 후보군을 대폭 줄이기 때문

- src/main/java/kr/co/programmersoop/example/section_01_07/hash_code/SomeObject.java

...
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        SomeObject that = (SomeObject) o;
        return intField == that.intField && Objects.equals(stringField, that.stringField);
    }

    // hashCode가 오버라이딩 되고 안되고의 차이
    @Override
    public int hashCode() {
        return Objects.hash(intField, stringField);
    }
...


- src/main/java/kr/co/programmersoop/example/section_01_07/hash_code/HashCodeExampleMain.java

public class HashCodeExampleMain {
    public static void main(String[] args) {
        // Hash 관련 컬렉션이 같은 인스턴스를 구분하는 방법
        // hashCode 비교 -> equals 비교
        
        SomeObject sameObject1 = new SomeObject(1, "programmers");
        SomeObject sameObject2 = new SomeObject(1, "programmers");

        System.out.println(sameObject1.hashCode());
        System.out.println(sameObject2.hashCode());

        Set<SomeObject> set = new HashSet<>();

        set.add(sameObject1);
        set.add(sameObject2);

        System.out.println(set.size());
    }
}


Set 자료형은 동일한 값을 오직 하나만 저장하는 특성이 있다.
hashCode 비교 후 equals 비교를 하는데, 여기서 오버라이딩 한 hashCode() 메서드나 equals() 둘 중 하나만 주석처리 해도 다른 인스턴스로 인식하여 set.size()가 2로 나온다.


5. toString()
toString() 메서드는 인스턴스를 문자열로 만드는 것
-> 대부분의 경우 로그를 남기기 위해 인스턴스를 문자열로 만든다.

서비스 개발하고 운영시 발생하는 로그가 있는데,
로그를 남기는 이유는 서비스 운영과정에서 발생하는 문제 인지 및 해결, 법적으로 로그 남겨야 하는 경우가 있다.

로그 남길 때 핵심은 시스템에서 어떤 데이터가 처리되었는가 이다.
데이터는 자바 애플리케이션 내에서 인스턴스 형태로 존재한다.
즉, 데이터를 로그로 남긴다는 것은 인스턴스를 문자열로 바꿔 로그로 남긴다는 것이다.

toString() 메서드가 호출되는 시점 : 레퍼런스 변수를 문자열과 더하기 연산 할 때

- src/main/java/kr/co/programmersoop/example/section_01_07/to_string/SomeObject.java

...
    @Override
    public String toString() {
        return "SomeObject{" +
                "intField=" + intField +
                ", stringField='" + stringField + '\'' +
                '}';
    }
...


오버라이딩 된 toString() 메서드 생성 방법 : 마우스 우클릭 > 생성 > toString() > 템플릿 : String concat (+) / intField: int, stringField: String 선택 > 확인

- src/main/java/kr/co/programmersoop/example/section_01_07/to_string/ToStringExampleMain.java

public class ToStringExampleMain {
    public static void main(String[] args) {
        SomeObject someObject1 = new SomeObject(1, "programmers");
        SomeObject someObject2 = new SomeObject(100, "foo");

        System.out.println(someObject1);
        System.out.println(someObject2);
    }
}


System.out.println();으로 찍을 때에도 toString() 메서드가 자동 호출 된다.


6. Objects 클래스는 NPE(NullPointerException)를 피할 수 있게 도와줌

SomeObject someObject = returnNullMethod();

someObject.hashCode(); // NPE

if (sameObject != null) { sameObject.hashCode() } // null 체크

Objects.hashCode(someObject); // null 체크 안해도, NPE 피하는 코드 : if문 줄여 가독성 높임



참고링크 : https://school.programmers.co.kr/learn/courses/17778/17778-%EC%8B%A4%EB%AC%B4-%EC%9E%90%EB%B0%94-%EA%B0%9C%EB%B0%9C%EC%9D%84-%EC%9C%84%ED%95%9C-oop%EC%99%80-%ED%95%B5%EC%8B%AC-%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4

 

실무 자바 개발을 위한 OOP와 핵심 디자인 패턴

@media (max-width: 991px) { .content { width: 100%; } } #landingPage { width: 100%; max-width: 848px; padding: 0 20px; letter-spacing: -0.02em; overflow-wrap: break-word; word-break: keep-all; word-wrap: break-word; } @media (max-width: 991px) {

school.programmers.co.kr

'강의 실습 > 실무 자바 개발을 위한 OOP와 핵심 디자인 패턴' 카테고리의 다른 글

if문 제거하기  (0) 2026.01.26
Optional  (0) 2026.01.25
예외  (0) 2026.01.22
Enum  (0) 2026.01.21
추상 클래스와 인터페이스  (0) 2026.01.20

댓글