백고등어 개발 블로그
코틀린 강의 5강: 클래스와 객체 본문
728x90
반응형
5강: 클래스와 객체
클래스 선언
코틀린에서 클래스는 class 키워드로 선언합니다.
기본 클래스
class Person {
var name: String = ""
var age: Int = 0
fun introduce() {
println("안녕하세요, 저는 $name이고 ${age}세입니다.")
}
}
fun main() {
val person = Person()
person.name = "김코틀린"
person.age = 25
person.introduce() // 안녕하세요, 저는 김코틀린이고 25세입니다.
}
생성자
주 생성자(Primary Constructor)
클래스 헤더에 선언하는 생성자입니다:
class Person(val name: String, val age: Int) {
fun introduce() {
println("안녕하세요, 저는 $name이고 ${age}세입니다.")
}
}
fun main() {
val person = Person("김코틀린", 25)
person.introduce()
}
init 블록에서 초기화 로직을 작성할 수 있습니다:
class Person(val name: String, val age: Int) {
init {
println("Person 객체가 생성되었습니다: $name")
}
init {
require(age >= 0) { "나이는 0 이상이어야 합니다" }
}
}
부 생성자(Secondary Constructor)
constructor 키워드로 추가 생성자를 정의할 수 있습니다:
class Person(val name: String) {
var age: Int = 0
constructor(name: String, age: Int) : this(name) {
this.age = age
}
fun introduce() {
println("이름: $name, 나이: $age")
}
}
fun main() {
val person1 = Person("김코틀린")
val person2 = Person("이자바", 30)
person1.introduce() // 이름: 김코틀린, 나이: 0
person2.introduce() // 이름: 이자바, 나이: 30
}
프로퍼티
getter와 setter
코틀린의 프로퍼티는 자동으로 getter와 setter를 제공합니다:
class Rectangle(var width: Int, var height: Int) {
// 커스텀 getter
val area: Int
get() = width * height
// 커스텀 setter
var size: Int
get() = width * height
set(value) {
// 정사각형으로 만들기
val side = kotlin.math.sqrt(value.toDouble()).toInt()
width = side
height = side
}
}
fun main() {
val rect = Rectangle(5, 10)
println("면적: ${rect.area}") // 50
rect.size = 100
println("너비: ${rect.width}, 높이: ${rect.height}") // 10, 10
}
지연 초기화(Late Initialization)
lateinit 키워드로 나중에 초기화할 프로퍼티를 선언할 수 있습니다:
class MyTest {
lateinit var testData: String
fun setup() {
testData = "테스트 데이터"
}
fun test() {
if (::testData.isInitialized) {
println(testData)
}
}
}
지연 계산(Lazy Initialization)
lazy 위임을 사용하면 처음 사용될 때 초기화됩니다:
class DataLoader {
val heavyData: String by lazy {
println("데이터 로딩 중...")
"무거운 데이터"
}
}
fun main() {
val loader = DataLoader()
println("객체 생성 완료")
println(loader.heavyData) // 이 시점에 "데이터 로딩 중..." 출력
println(loader.heavyData) // 캐시된 값 사용
}
데이터 클래스(Data Class)
데이터를 담는 클래스를 쉽게 만들 수 있습니다:
data class User(val name: String, val age: Int, val email: String)
fun main() {
val user1 = User("김코틀린", 25, "kotlin@example.com")
val user2 = User("김코틀린", 25, "kotlin@example.com")
// 자동 생성된 toString()
println(user1) // User(name=김코틀린, age=25, email=kotlin@example.com)
// 자동 생성된 equals()
println(user1 == user2) // true
// 자동 생성된 copy()
val user3 = user1.copy(age = 26)
println(user3) // User(name=김코틀린, age=26, email=kotlin@example.com)
// 구조 분해 선언
val (name, age, email) = user1
println("이름: $name, 나이: $age")
}
데이터 클래스는 다음을 자동으로 생성합니다:
- equals() / hashCode()
- toString()
- copy()
- componentN() 함수들
상속
코틀린의 모든 클래스는 기본적으로 final입니다. 상속을 허용하려면 open 키워드를 사용해야 합니다:
open class Animal(val name: String) {
open fun makeSound() {
println("동물 소리")
}
}
class Dog(name: String) : Animal(name) {
override fun makeSound() {
println("멍멍!")
}
}
class Cat(name: String) : Animal(name) {
override fun makeSound() {
println("야옹!")
}
}
fun main() {
val dog = Dog("바둑이")
val cat = Cat("나비")
dog.makeSound() // 멍멍!
cat.makeSound() // 야옹!
}
추상 클래스(Abstract Class)
abstract class Shape {
abstract val area: Double
abstract fun draw()
// 일반 함수도 포함 가능
fun describe() {
println("이 도형의 면적은 $area입니다.")
}
}
class Circle(val radius: Double) : Shape() {
override val area: Double
get() = Math.PI * radius * radius
override fun draw() {
println("원을 그립니다. 반지름: $radius")
}
}
fun main() {
val circle = Circle(5.0)
circle.draw()
circle.describe()
}
인터페이스(Interface)
interface Drawable {
fun draw()
// 기본 구현 제공 가능
fun description() {
println("그릴 수 있는 객체입니다.")
}
}
interface Clickable {
fun click()
fun showClick() = println("클릭됨") // 기본 구현
}
class Button : Drawable, Clickable {
override fun draw() {
println("버튼을 그립니다.")
}
override fun click() {
println("버튼이 클릭되었습니다!")
}
}
fun main() {
val button = Button()
button.draw()
button.click()
button.description()
}
가시성 제한자(Visibility Modifiers)
- public: 모든 곳에서 접근 가능 (기본값)
- private: 클래스 내부에서만 접근 가능
- protected: 클래스와 하위 클래스에서 접근 가능
- internal: 같은 모듈 내에서만 접근 가능
open class BankAccount {
private var balance: Double = 0.0
protected var accountNumber: String = ""
fun deposit(amount: Double) {
balance += amount
}
fun getBalance(): Double = balance
}
class SavingsAccount : BankAccount() {
fun setAccountNumber(number: String) {
accountNumber = number // protected 접근 가능
}
}
중첩 클래스와 내부 클래스
중첩 클래스(Nested Class)
class Outer {
private val outerProperty = "외부 클래스"
class Nested {
fun hello() {
println("중첩 클래스")
// outerProperty에 접근 불가
}
}
}
fun main() {
val nested = Outer.Nested()
nested.hello()
}
내부 클래스(Inner Class)
inner 키워드를 사용하면 외부 클래스의 멤버에 접근할 수 있습니다:
class Outer {
private val outerProperty = "외부 클래스"
inner class Inner {
fun hello() {
println("내부 클래스")
println(outerProperty) // 접근 가능
}
}
}
fun main() {
val inner = Outer().Inner()
inner.hello()
}
싱글톤 패턴(Object Declaration)
object 키워드로 싱글톤을 쉽게 만들 수 있습니다:
object DatabaseConnection {
private var connectionCount = 0
fun connect() {
connectionCount++
println("연결됨. 총 연결 수: $connectionCount")
}
fun getConnectionCount() = connectionCount
}
fun main() {
DatabaseConnection.connect()
DatabaseConnection.connect()
println("총 연결: ${DatabaseConnection.getConnectionCount()}")
}
동반 객체(Companion Object)
클래스 내부에서 정적 멤버처럼 사용할 수 있습니다:
class User private constructor(val name: String) {
companion object {
private var userCount = 0
fun create(name: String): User {
userCount++
return User(name)
}
fun getUserCount() = userCount
}
}
fun main() {
val user1 = User.create("김코틀린")
val user2 = User.create("이자바")
println("생성된 사용자 수: ${User.getUserCount()}")
}
마치며
이번 강의에서는 코틀린의 클래스와 객체지향 프로그래밍에 대해 알아보았습니다. 데이터 클래스로 간결하게 데이터 모델을 만들 수 있고, object 선언으로 싱글톤을 쉽게 구현할 수 있다는 점이 코틀린의 큰 장점입니다. 다음 강의에서는 컬렉션에 대해 알아보겠습니다.
728x90
반응형
'코틀린 강의' 카테고리의 다른 글
| 코틀린 강의 7강: 예외 처리 (0) | 2025.10.28 |
|---|---|
| 코틀린 강의 6강: 컬렉션 (0) | 2025.10.28 |
| 코틀린 강의 4강: 함수와 람다 표현식 (0) | 2025.10.28 |
| 코틀린 강의 3강: 연산자와 제어문 (0) | 2025.10.28 |
| 코틀린 강의 2강: 변수와 자료형 (0) | 2025.10.28 |