with ChatGPT 시리즈는 ChatGPT의 내용과 개인의 생각을 토대로 학습해 보는 컨텐츠입니다.
Kotlin의 data class는 단순히 데이터를 위한 클래스를 쉽게 정의할 수 있도록 설계된 문법입니다.
Java의 POJO나 최근 도입된 record 보다도 더 간결하고 실용적이며, Kotlin 철학인 간결성, 안전성에 부합합니다.
이번 글에서는 다음 내용을 중심으로 설명하겠습니다:
- Kotlin의 data class 기본 구조
- 자동으로 생성되는 함수들
- Java의 POJO와의 비교
- Java의 record와의 차이
- 실무에서의 활용 예시
🔹 1. Kotlin의 data class란?
Kotlin에서 데이터를 담기 위한 클래스를 만들 때, data 키워드를 붙이면 여러 가지 함수들이 자동 생성됩니다.
data class User(val name: String, val age: Int)
이 한 줄로 다음과 같은 기능이 자동으로 제공됩니다:
- equals() / hashCode()
- toString()
- copy()
- componentN() (비구조화 선언 지원)
🔹 2. 자동으로 생성되는 함수들
val user1 = User("Alice", 30)
val user2 = user1.copy(age = 31)
println(user2) // User(name=Alice, age=31)
✅ copy()
- 기존 객체를 복사하면서 일부 프로퍼티만 변경 가능
- 불변 객체를 다룰 때 매우 유용
✅ componentN() - 구조 분해 지원
val (name, age) = user1
println("$name is $age years old") // Alice is 30 years old
- 내부적으로 component1(), component2()가 자동 생성됨
🔹 3. Java POJO와의 비교
Java에서 동일한 기능을 하는 클래스를 만들려면, 아래와 같이 상당한 코드가 필요합니다.
public class User {
private final String name;
private final int age;
public User(String name, int age) { ... }
public String getName() { ... }
public int getAge() { ... }
@Override public boolean equals(Object o) { ... }
@Override public int hashCode() { ... }
@Override public String toString() { ... }
}
- ✅ Kotlin은 한 줄로 동일한 기능을 구현 가능
- ❌ Java에서는 Lombok, IDE 자동 생성 없이 직접 구현해야 함
🔹 4. Java record와의 비교 (Java 14+)
Java record는 해당 글에서도 작성하였습니다.
Java 14부터 record가 도입되면서, 단순 데이터 클래스를 간결하게 정의할 수 있게 되었습니다.
public record User(String name, int age) { }
- ✅ 생성자, getter, equals, hashCode, toString 자동 생성됨
- ❌ copy(), componentN(), Destructuring은 지원되지 않음
- ❌ 커스텀 로직을 추가할 경우 compact constructor 사용 필요 -> 복잡해짐
- ❌ record는 상속 불가, 모든 필드는 final
✅ Kotlin data class vs Java record
항목 | Kotlin data class | Java record |
간결성 | ✅ 매우 간결 | ✅ 간결 |
커스텀 메서드 | ✅ 자유롭게 추가 가능 | ⚠️ 생성자/로직 작성 시 구조가 복잡해짐 |
구조 분해 (Destructuring) | ✅ componentN() 자동 지원 | ❌ 지원되지 않음 |
copy() 지원 | ✅ 기본 제공 | ❌ 직접 구현 필요 |
상속 | ❌ 불가 (final class) | ❌ 불가 (암묵적 final) |
불변성 | ✅ 기본적으로 val 사용 | ✅ 암묵적으로 final 필드 |
🔹 5. 실무에서의 활용 예시
✅ API 응답 객체
data class ApiResponse<T>(
val status: String,
val data: T?
)
✅ DTO, 이벤트 객체, Query Result 등에 자주 사용
data class UserRegisteredEvent(
val userId: String,
val timestamp: LocalDateTime
)
✅ 컬렉션을 map/filter 할 때 구조 분해 활용
val users = listOf(User("Alice", 20), User("Bob", 30))
for ((name, age) in users) {
println("$name is "$age")
}
🚀 결론
- Kotlin의 data class는 POJO의 반복 코드를 제거하고, 함수형 프로그래밍과도 잘 어울리는 구조
- Java의 record도 좋은 대안이지만, Kotlin의 copy, Destructuring, componentN() 같은 기능은 아직 미지원
- 실무에서는 DTO, VO, 이벤트, 응답 바디 등 다양한 곳에서 광범위하게 활용됨
🤔 추가로 생각해 볼 질문들
- data class는 왜 상속이 불가능할까? 실무에서 문제가 되지는 않을까?
- data class와 sealed class를 함께 쓰면 어떤 시너지가 있을까?
- copy() 함수는 내부적으로 어떤 방식으로 동작할까?
- Kotlin에서 data class를 JSON 직렬화할 때 주의할 점은?
- componentN()이 어떻게 컴파일되는지 디컴파일로 확인해 볼 수 있을까?