Kotlin 클래스와 객체 | 클래스, 상속, 인터페이스
이 글의 핵심
Kotlin 클래스와 객체에 대한 실전 가이드입니다. 클래스, 상속, 인터페이스 등을 예제와 함께 상세히 설명합니다.
들어가며
클래스는 객체의 설계도에 해당하고, data class·sealed class 등으로 용도에 맞는 뼈대를 짧게 쓸 수 있습니다. 생성자·프로퍼티 문법이 Java보다 단순한 편입니다.
1. 클래스 기본
클래스 정의
class Person {
var name: String = ""
var age: Int = 0
fun introduce() {
println("안녕하세요, $name입니다. ${age}세입니다.")
}
}
val person = Person()
person.name = "홍길동"
person.age = 25
person.introduce()
주 생성자
class Person(val name: String, var age: Int) {
fun introduce() {
println("안녕하세요, $name입니다. ${age}세입니다.")
}
}
val person = Person("홍길동", 25)
init 블록
class Person(val name: String, var age: Int) {
init {
println("Person 객체 생성: $name")
require(age >= 0) { "나이는 0 이상이어야 합니다" }
}
}
부 생성자
class Person(val name: String) {
var age: Int = 0
constructor(name: String, age: Int) : this(name) {
this.age = age
}
}
val person1 = Person("홍길동")
val person2 = Person("김철수", 30)
2. 프로퍼티
getter/setter
class Person(val name: String) {
var age: Int = 0
get() = field
set(value) {
if (value >= 0) {
field = value
}
}
val isAdult: Boolean
get() = age >= 18
}
지연 초기화
class MyClass {
lateinit var name: String
fun init() {
name = "홍길동"
}
fun isInitialized() = ::name.isInitialized
}
3. 상속
open 클래스
Kotlin 클래스는 기본적으로 final이므로 상속하려면 open 키워드가 필요합니다:
// open: 상속 가능한 클래스
// Kotlin은 기본적으로 모든 클래스가 final (상속 불가)
// 상속을 허용하려면 명시적으로 open 선언
open class Animal(val name: String) {
// open: 오버라이딩 가능한 메서드
// 메서드도 기본적으로 final
// 자식 클래스에서 재정의하려면 open 필요
open fun makeSound() {
println("동물 소리")
}
// open이 없는 메서드는 final (오버라이딩 불가)
fun sleep() {
println("$name이(가) 잠을 잡니다.")
}
}
// Dog 클래스: Animal을 상속
class Dog(name: String) : Animal(name) {
// : Animal(name) : 부모 생성자 호출
// name을 부모 클래스에 전달
// override: 부모 메서드 재정의
override fun makeSound() {
println("멍멍!")
}
// Dog만의 메서드
fun fetch() {
println("$name이(가) 공을 가져옵니다.")
}
}
// Cat 클래스: Animal을 상속
class Cat(name: String) : Animal(name) {
override fun makeSound() {
println("야옹!")
}
fun scratch() {
println("$name이(가) 할퀴기를 합니다.")
}
}
// 사용 예제
fun main() {
val dog = Dog("바둑이")
dog.makeSound() // 멍멍! (오버라이딩)
dog.sleep() // 바둑이이(가) 잠을 잡니다. (상속)
dog.fetch() // 바둑이이(가) 공을 가져옵니다. (Dog 고유)
val cat = Cat("나비")
cat.makeSound() // 야옹! (오버라이딩)
cat.sleep() // 나비이(가) 잠을 잡니다. (상속)
cat.scratch() // 나비이(가) 할퀴기를 합니다. (Cat 고유)
// 다형성
val animals: List<Animal> = listOf(
Dog("멍멍이"),
Cat("야옹이")
)
for (animal in animals) {
animal.makeSound() // 각 객체의 실제 타입에 따라 호출
// 멍멍!
// 야옹!
}
}
open vs final 비교:
// ❌ final 클래스 (기본)
class FinalClass {
fun method() {}
}
// class SubClass : FinalClass() // 컴파일 에러!
// This type is final, so it cannot be inherited from
// ✅ open 클래스
open class OpenClass {
open fun method() {}
}
class SubClass : OpenClass() {
override fun method() {} // OK
}
왜 기본이 final인가:
- 안전성: 의도하지 않은 상속 방지
- 성능: final 메서드는 최적화 가능
- 명확성: 상속 가능 여부가 명시적
abstract 클래스
abstract class Shape {
abstract fun area(): Double
abstract fun perimeter(): Double
fun describe() {
println("넓이: ${area()}, 둘레: ${perimeter()}")
}
}
class Circle(val radius: Double) : Shape() {
override fun area() = Math.PI * radius * radius
override fun perimeter() = 2 * Math.PI * radius
}
class Rectangle(val width: Double, val height: Double) : Shape() {
override fun area() = width * height
override fun perimeter() = 2 * (width + height)
}
4. 인터페이스
기본 인터페이스
interface Drawable {
fun draw()
fun erase() {
println("지우기") // 기본 구현
}
}
class Circle : Drawable {
override fun draw() {
println("원 그리기")
}
}
다중 인터페이스
interface Clickable {
fun click()
}
interface Focusable {
fun focus()
}
class Button : Clickable, Focusable {
override fun click() {
println("버튼 클릭")
}
override fun focus() {
println("버튼 포커스")
}
}
5. 데이터 클래스
기본 사용
data class User(
val name: String,
val age: Int,
val email: String
)
val user1 = User("홍길동", 25, "[email protected]")
val user2 = User("홍길동", 25, "[email protected]")
println(user1 == user2) // true (equals 자동 생성)
println(user1) // User(name=홍길동, age=25, [email protected])
copy 메서드
val user1 = User("홍길동", 25, "[email protected]")
val user2 = user1.copy(age = 26)
println(user1) // age=25
println(user2) // age=26
구조 분해
val user = User("홍길동", 25, "[email protected]")
val (name, age, email) = user
println("이름: $name, 나이: $age")
6. Sealed 클래스
sealed class Result {
data class Success(val data: String) : Result()
data class Error(val message: String) : Result()
object Loading : Result()
}
fun handleResult(result: Result) {
when (result) {
is Result.Success -> println("성공: ${result.data}")
is Result.Error -> println("에러: ${result.message}")
is Result.Loading -> println("로딩 중...")
}
}
7. Object 선언
싱글톤
object Database {
private var connection: String? = null
fun connect() {
connection = "Connected"
println("데이터베이스 연결됨")
}
fun disconnect() {
connection = null
println("데이터베이스 연결 해제됨")
}
}
Database.connect()
Companion Object
class User(val name: String) {
companion object {
const val MAX_AGE = 150
fun create(name: String): User {
return User(name)
}
}
}
val user = User.create("홍길동")
println(User.MAX_AGE)
8. 실전 예제
예제: 쇼핑 시스템
data class Product(
val id: String,
val name: String,
val price: Int
)
data class CartItem(
val product: Product,
var quantity: Int
)
class ShoppingCart {
private val items = mutableListOf<CartItem>()
fun addItem(product: Product, quantity: Int = 1) {
val existing = items.find { it.product.id == product.id }
if (existing != null) {
existing.quantity += quantity
} else {
items.add(CartItem(product, quantity))
}
}
fun removeItem(productId: String) {
items.removeIf { it.product.id == productId }
}
fun getTotalPrice(): Int {
return items.sumOf { it.product.price * it.quantity }
}
fun printCart() {
println("=== 장바구니 ===")
items.forEach {
println("${it.product.name} x${it.quantity} = ${it.product.price * it.quantity}원")
}
println("총액: ${getTotalPrice()}원")
}
}
fun main() {
val cart = ShoppingCart()
cart.addItem(Product("P001", "노트북", 1000000))
cart.addItem(Product("P002", "마우스", 30000), 2)
cart.printCart()
}
정리
핵심 요약
- 클래스: 주 생성자, init 블록
- 상속: open, override
- 인터페이스: 다중 구현 가능
- 데이터 클래스: equals, hashCode, copy 자동
- Sealed 클래스: 제한된 상속
- Object: 싱글톤, Companion Object
다음 단계
- Kotlin 컬렉션
- Kotlin 코루틴
- Kotlin Android 개발
관련 글
- Java 클래스와 객체 | OOP, 상속, 인터페이스
- JavaScript 클래스 | ES6 Class 문법 완벽 정리
- Python 클래스 | 객체지향 프로그래밍(OOP) 완벽 정리
- C++ 클래스와 객체 |
- C++ 상속과 다형성 |