📦 데이터 클래스
📖 데이터 클래스란?
**데이터 클래스(Data Class)**는 데이터를 보관하는 특별한 클래스입니다. 자동으로 유용한 메서드들을 생성해줍니다.
💡 기본 사용법
일반 클래스 vs 데이터 클래스
// 일반 클래스
class Person1(val name: String, val age: Int)
// 데이터 클래스
data class Person2(val name: String, val age: Int)
fun main() {
val p1 = Person1("홍길동", 25)
val p2 = Person2("홍길동", 25)
println(p1) // Person1@해시코드
println(p2) // Person2(name=홍길동, age=25) ← 자동 toString!
}
자동 생성 메서드
data class Person(val name: String, val age: Int)
fun main() {
val person = Person("홍길동", 25)
// toString() - 자동 생성
println(person) // Person(name=홍길동, age=25)
// equals() - 내용 비교
val other = Person("홍길동", 25)
println(person == other) // true
// hashCode() - 해시 코드
println(person.hashCode())
// copy() - 복사
val copy = person.copy()
println(copy) // Person(name=홍길동, age=25)
}
🔧 copy 메서드
부분 수정
data class Person(val name: String, val age: Int, val email: String)
fun main() {
val person = Person("홍길동", 25, "hong@example.com")
// 나이만 변경
val older = person.copy(age = 30)
println(older)
// Person(name=홍길동, age=30, email=hong@example.com)
// 이메일만 변경
val newEmail = person.copy(email = "new@example.com")
println(newEmail)
}
불변성 유지
data class Point(val x: Int, val y: Int)
fun main() {
val point1 = Point(10, 20)
// 새로운 객체 생성 (원본 유지)
val point2 = point1.copy(x = 30)
println(point1) // Point(x=10, y=20) ← 변경 안 됨!
println(point2) // Point(x=30, y=20)
}
🎯 구조 분해
기본 구조 분해
data class Person(val name: String, val age: Int)
fun main() {
val person = Person("홍길동", 25)
// 구조 분해 선언
val (name, age) = person
println("이름: $name") // 홍길동
println("나이: $age") // 25
}
일부만 사용
data class Person(val name: String, val age: Int, val email: String)
fun main() {
val person = Person("홍길동", 25, "hong@example.com")
// 필요한 것만
val (name, _) = person // _ 로 무시
println("이름: $name")
// 순서 중요!
val (_, age) = person
println("나이: $age")
}
리스트와 함께
data class Person(val name: String, val age: Int)
fun main() {
val people = listOf(
Person("Alice", 25),
Person("Bob", 30),
Person("Charlie", 35)
)
for ((name, age) in people) {
println("$name: ${age}세")
}
// Alice: 25세
// Bob: 30세
// Charlie: 35세
}
🎯 실전 예제
좌표
data class Point(val x: Int, val y: Int) {
fun distance(other: Point): Double {
val dx = (x - other.x).toDouble()
val dy = (y - other.y).toDouble()
return kotlin.math.sqrt(dx * dx + dy * dy)
}
}
fun main() {
val p1 = Point(0, 0)
val p2 = Point(3, 4)
println("거리: %.2f".format(p1.distance(p2))) // 5.00
// copy로 이동
val p3 = p1.copy(x = 10)
println(p3) // Point(x=10, y=0)
}
사용자 정보
data class User(
val id: Int,
val username: String,
val email: String,
val isActive: Boolean = true
)
fun main() {
val user = User(
id = 1,
username = "hong",
email = "hong@example.com"
)
println(user)
// 비활성화
val deactivated = user.copy(isActive = false)
println("활성 상태: ${deactivated.isActive}")
}
상품
data class Product(
val id: String,
val name: String,
val price: Int,
val stock: Int
) {
fun sell(quantity: Int): Product? {
return if (stock >= quantity) {
copy(stock = stock - quantity)
} else {
null
}
}
}
fun main() {
var product = Product("P001", "노트북", 1500000, 10)
println(product)
// 3개 판매
product = product.sell(3) ?: product
println(product) // stock: 7
// 20개 판매 시도 (재고 부족)
val result = product.sell(20)
println(result) // null
}
API 응답
data class ApiResponse<T>(
val success: Boolean,
val data: T?,
val message: String = ""
)
data class User(val id: Int, val name: String)
fun main() {
// 성공
val success = ApiResponse(
success = true,
data = User(1, "홍길동")
)
println(success)
// 실패
val failure = ApiResponse<User>(
success = false,
data = null,
message = "사용자를 찾을 수 없습니다"
)
println(failure)
}
🔍 equals와 hashCode
동등성 비교
data class Person(val name: String, val age: Int)
fun main() {
val p1 = Person("홍길동", 25)
val p2 = Person("홍길동", 25)
val p3 = Person("김철수", 25)
// 내용 비교 (자동 equals)
println(p1 == p2) // true
println(p1 == p3) // false
// 참조 비교
println(p1 === p2) // false (다른 객체)
}
Set과 Map에서 사용
data class Person(val name: String, val age: Int)
fun main() {
val set = setOf(
Person("홍길동", 25),
Person("홍길동", 25), // 중복 제거됨
Person("김철수", 30)
)
println(set.size) // 2
val map = mapOf(
Person("홍길동", 25) to "학생",
Person("김철수", 30) to "선생님"
)
println(map[Person("홍길동", 25)]) // 학생
}
🤔 자주 묻는 질문
Q1. 언제 data class를 쓰나요?
A: 데이터만 보관할 때!
// ✅ 데이터만 보관 → data class
data class User(val id: Int, val name: String)
// ❌ 동작이 많으면 일반 class
class BankAccount(private var balance: Int) {
fun deposit(amount: Int) { ... }
fun withdraw(amount: Int) { ... }
}
Q2. var도 쓸 수 있나요?
A: 가능하지만 val 권장!
// 가능
data class Person(var name: String, var age: Int)
fun main() {
val person = Person("홍길동", 25)
person.age = 26 // 변경 가능
// 하지만 불변(val)이 더 안전!
data class ImmutablePerson(val name: String, val age: Int)
}
Q3. 상속할 수 있나요?
A: open class는 상속 가능, data class는 불가!
// ✅ 일반 클래스 상속 가능
open class Animal
data class Dog(val name: String) : Animal()
// ❌ data class는 상속 불가
data class Animal(val name: String)
// class Dog : Animal() // 오류!
Q4. componentN은 뭔가요?
A: 구조 분해의 내부 구현!
data class Person(val name: String, val age: Int)
fun main() {
val person = Person("홍길동", 25)
// 구조 분해
val (name, age) = person
// 실제로는 이렇게 동작
val name2 = person.component1() // name
val age2 = person.component2() // age
}
🎬 마치며
데이터 클래스로 간편하게 데이터를 다루세요!
핵심 정리: