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문 줄여 가독성 높임
실무 자바 개발을 위한 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 |
댓글