Notice
Recent Posts
Recent Comments
Link
변수의 기록
(자바) 자바의 신 day5 - 자바에서 업캐스팅과 다운캐스팅, equals와 hashCode, toString의 역할 및 오버라이딩 이유 본문
자바/자바
(자바) 자바의 신 day5 - 자바에서 업캐스팅과 다운캐스팅, equals와 hashCode, toString의 역할 및 오버라이딩 이유
불광동 물주먹 2025. 6. 25. 06:00자바에서 업캐스팅과 다운캐스팅, equals와 hashCode, toString의 역할 및 오버라이딩 이유
1. 업캐스팅과 다운캐스팅의 원리와 목적
✅ 업캐스팅 (Upcasting)
- 자식 객체를 부모 타입으로 참조하는 것
- 예: Parent p = new Child();
- 자동 형변환이 일어나며, 부모가 가진 멤버만 접근 가능
- 런타임 시에는 실제 객체가 Child이더라도, 컴파일러는 Parent 기준으로 접근 허용
- 다형성의 핵심: 다양한 자식 객체를 하나의 부모 타입으로 묶어 공통된 방식으로 처리 가능
✅ 다운캐스팅 (Downcasting)
- 부모 타입으로 참조된 객체를 다시 자식 타입으로 변환
- 예: Child c = (Child) p;
- 명시적 형변환이 필요하며, 실제 객체가 해당 자식 타입일 때만 안전하게 가능
- 그렇지 않으면 ClassCastException 발생
- 안전한 다운캐스팅을 위해 instanceof 사용 권장:
- if (p instanceof Child) { Child c = (Child) p; }
✅ 왜 굳이 업/다운캐스팅을 쓸까?
- 다형성을 통해 여러 자식 타입을 하나의 부모 타입 컬렉션(List, Set 등)으로 처리 가능
- 유지보수성과 확장성을 높이기 위해 인터페이스나 추상 클래스를 기준으로 설계하고 업캐스팅하여 통합 처리함
2. toString() 오버라이딩의 이유
✅ Object 클래스의 toString()
- 자바의 모든 클래스는 Object 클래스를 상속함 (암묵적으로)
- Object.toString() 기본 구현은 다음과 같음:
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
- 출력 예시: User@3e3abc88
- 클래스명과 해시코드를 문자열로 반환하지만, 객체 내용은 보이지 않음
✅ 오버라이딩 이유 (Lombok을 사용하지 않는 경우)
- 객체의 내부 상태(필드 값 등)를 사람이 읽을 수 있게 표현하기 위함
- 디버깅, 로그 출력, 테스트 시 가독성을 높임
- Lombok의 @ToString, @Data는 자동 생성 지원
@Override
public String toString() {
return "User{name='" + name + "', age=" + age + "}";
}
3. equals() 오버라이딩의 이유
✅ 기본 equals() 동작 (Object)
public boolean equals(Object obj) {
return this == obj;
}
- 기본은 주소 비교 → 내용이 같아도 false 나옴
✅ DTO에서 equals() 오버라이딩 이유 (Lombok을 사용하지 않는 경우)
- DTO는 값 중심 객체이므로, 내부 필드 값이 같으면 같다고 판단해야 함
- 컬렉션(Set, Map 등)에서의 비교, 중복 제거 시 정확한 동작을 위해 필수
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
UserDTO user = (UserDTO) o;
return age == user.age && Objects.equals(name, user.name);
}
✅ 단, 대부분의 실무 DTO는 Lombok을 사용하므로 @EqualsAndHashCode 또는 @Data 어노테이션으로 자동 생성하는 것이 일반적이다.
4. hashCode() 오버라이딩의 이유
✅ Object 클래스의 hashCode()
- 기본 구현은 객체의 메모리 주소 기반 정보를 정수값으로 변환한 해시값을 반환함
- 직접 메모리 주소는 아니며, 객체의 ID나 JVM 내부 알고리즘에 의해 계산된 숫자
- 기본 구현 예시:
public native int hashCode();
✅ 왜 오버라이딩해야 하나? (Lombok을 사용하지 않는 경우)
- HashSet, HashMap, Hashtable 등 해시 기반 컬렉션에서 객체 비교 시 hashCode()로 먼저 비교 후 equals() 수행
- 값이 같으면 동일한 해시코드가 나와야 함 → equals와 hashCode는 항상 쌍으로 오버라이딩
@Override
public int hashCode() {
return Objects.hash(name, age);
}
✅ 자바의 규약
- equals() == true 이면 hashCode()도 같아야 함
- hashCode()만 같고 equals()는 다를 수 있음 (충돌은 허용됨)
5. Lombok이 자동으로 해주는 것
어노테이션 toString() equals/hashCode() getter/setter
@ToString | ✅ | ❌ | ❌ |
@EqualsAndHashCode | ❌ | ✅ | ❌ |
@Data | ✅ | ✅ | ✅ |
@Value (불변 DTO) | ✅ | ✅ | ✅ (final) |
6. 실무 설계 팁 및 확장 내용
- 다운캐스팅이 자주 보인다면 설계를 재검토해야 함 (인터페이스나 추상 메서드로 해결 가능)
- equals/hashCode 없이 HashSet 등에 DTO를 넣으면 중복 데이터 비교가 불가능해짐
- record(Java 14+)를 사용하면 toString(), equals(), hashCode() 자동 생성됨
public record UserDTO(String name, int age) {}
7. 결론 정리
- 업캐스팅은 다형성을 위해, 다운캐스팅은 자식 고유 기능을 쓸 때만 제한적으로 사용
- **toString()**은 객체를 사람이 보기 쉽게, **equals/hashCode()**는 값 비교를 위해 필수
- Lombok이나 record를 활용하면 코드량은 줄고 명확한 객체 정의 가능
- 실무에서는 equals/hashCode 오버라이딩 여부에 따라 동작이 완전히 달라지므로 반드시 주의할 것
'자바 > 자바' 카테고리의 다른 글
(자바) 내부 클래스란? (자바의 신 day7) (0) | 2025.07.01 |
---|---|
(자바)자바의 신 day6 - Java String 완벽 정리: intern(), 문자열 덧셈, 최적화 (0) | 2025.06.29 |
(자바) 스프링과 리플렉션 정리2 (0) | 2025.06.25 |
(자바) 자바의 신 day4 - 상속 기본 (생성자 규칙 + 오버라이딩) (0) | 2025.06.24 |
(자바) 리플렉션의 개념 * 예제 (0) | 2025.06.23 |