λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
Kotlin

[Kotlin] - Class(클래슀)

by 주발2 2021. 10. 17.
λ°˜μ‘ν˜•

πŸ“Ž Kotlin - Class(클래슀)

μ•ˆλ…•ν•˜μ„Έμš”, 이번 μ‹œκ°„μ—λŠ” μ½”ν‹€λ¦° ν΄λž˜μŠ€μ— λŒ€ν•΄ μ •λ¦¬ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

 

이번 개인 ν”„λ‘œμ νŠΈμ—μ„œ 코틀린을 처음 μ‚¬μš©ν•΄μ„œ κ°œλ°œμ„ μ§„ν–‰ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€λ§Œ.. 아직 코틀린은 λ‚―μ„€κΈ°λ§Œ ν•˜λ„€μš”..

  • forλ¬Έ, λ°°μ—΄ 생성, μƒμ„±μž, open ν‚€μ›Œλ“œ, λΆˆλ³€, ?, !, !! λ“±λ“± ...

기쑴에 μ‚¬μš©ν•˜λŠ” μžλ°”μ™€λŠ” λ¬Έλ²•μ μœΌλ‘œ λ‹€λ₯ΈλΆ€λΆ„이 κ½€(?) μ‘΄μž¬ν•˜κΈ° λ•Œλ¬Έμ— 단기간에 μΉœν•΄μ§€κΈ°κ°€ νž˜λ“  것 κ°™μŠ΅λ‹ˆλ‹€.

μžλ°”μ— μ΅μˆ™ν•˜λ‹€λ©΄ 코틀린은 일주일정도면 μΆ©λΆ„ν•˜λ‹€.. λΌλŠ” 글을 λ³Έ 적이 μžˆμ—ˆλŠ”λ°μš”, μ €λŠ” 아직 μžλ°”μ— μ΅μˆ™ν•˜μ§€κ°€ μ•Šλ‚˜λ΄…λ‹ˆλ‹€ 😭

 

μ•žμœΌλ‘œ ν—·κ°ˆλ¦¬λŠ” 뢀뢄이 μƒκΈΈλ•Œλ§ˆλ‹€ ν‹ˆν‹ˆνžˆ μ½”ν‹€λ¦°μ—λŒ€ν•΄ 정리λ₯Ό ν•˜λ €κ³ ν•©λ‹ˆλ‹€.

이번 μ‹œκ°„μ— 정리할 λ‚΄μš©μ€ ν΄λž˜μŠ€μž…λ‹ˆλ‹€. μ½”ν‹€λ¦°μ—μ„œμ˜ ν΄λž˜μŠ€λŠ” μƒμ„±μžλ‚˜ open ν‚€μ›Œλ“œ, companion object λ“±λ“± μžλ°”μ—λŠ” μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” ν‚€μ›Œλ“œλ“€μ΄ μ‘΄μž¬ν•˜κΈ° λ•Œλ¬Έμ— 처음 μ ‘ν•œλ‹€λ©΄ ν—·κ°ˆλ¦΄ 수 μžˆλŠ”λ°μš”, 이에 λŒ€ν•΄ μ •λ¦¬ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

 

ν•΄λ‹Ή ν¬μŠ€νŒ…μ€ μ½”ν‹€λ¦°μ˜ κ³΅μ‹λ¬Έμ„œλ₯Ό μ°Έκ³ ν•˜μ—¬ μž‘μ„±ν•˜μ˜€μŠ΅λ‹ˆλ‹€. 

 

 

 

Classes


μ½”ν‹€λ¦°μ˜ ν΄λž˜μŠ€λŠ” μžλ°”μ™€ λ™μΌν•˜κ²Œ class ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ μ„ μ–Έν•  수 μžˆμŠ΅λ‹ˆλ‹€.

class Person { /* .. */ }

 

클래슀의 선언은 이름과 헀더뢀뢄, λ°”λ””λΆ€λΆ„μœΌλ‘œ ꡬ성이 λ©λ‹ˆλ‹€.

  • Header : νƒ€μž… νŒŒλΌλ―Έν„°, μ£Ό μƒμ„±μž, 기타 λ“±λ“±

헀더뢀뢄과 바디뢀뢄은 μ„ νƒμ μœΌλ‘œ μ•„λž˜ λΆ€λΆ„μ—μ„œ λ‹€μ‹œ μ„€λͺ…λ“œλ¦¬κ² μŠ΅λ‹ˆλ‹€.

 

 

Constructor(μƒμ„±μž)


μ €λŠ” μ½”ν‹€λ¦°μ—μ„œ 이 μƒμ„±μž 뢀뢄이 ꡉμž₯히 ν—·κ°ˆλ ΈμŠ΅λ‹ˆλ‹€. 어떀곳은 μ†Œκ΄„ν˜Έλ₯Ό, 어떀곳은 μ€‘κ΄„ν˜Έλ₯Ό μ‚¬μš©ν•˜λŠ”λ° 뭐가뭔지 λͺ°λžμ—ˆλŠ”λ°μš”, μ–Έμ œ μ–΄λ– ν•œ 방식을 μ‚¬μš©ν•˜λŠ”μ§€ μ•Œμ•„λ³΄κ² μŠ΅λ‹ˆλ‹€.

 

λ¨Όμ € μ½”ν‹€λ¦°μ—μ„œ μƒμ„±μžλŠ” μ£Ό μƒμ„±μž(Primary Constructor)와 ν•œ 개 μ΄μƒμ˜ λΆ€ μƒμ„±μž(Secondary Constructors)κ°€ μžˆμŠ΅λ‹ˆλ‹€.

μ£Ό μƒμ„±μžλŠ” 클래슀 헀더뢀뢄에 μž‘μ„±ν•˜λ©° 클래슀 이름 λ‹€μŒμ— μž‘μ„±ν•˜κ³ , λ°˜λ“œμ‹œ ν•„μˆ˜λŠ” μ•„λ‹™λ‹ˆλ‹€.

λ˜ν•œ μ£Ό μƒμ„±μžμ—λŠ” μ–΄λ– ν•œ μ½”λ“œλ„ 포함할 수 μ—†μŠ΅λ‹ˆλ‹€. 

class Person constructor(name: String)

// μ£Όμ„μ΄λ‚˜ κ°€μ‹œμ„± μ ‘κ·Όμž μ—†μœΌλ©΄ constructor μƒλž΅ κ°€λŠ₯
class Person(name: String)

 

 

 

μ΄ˆκΈ°ν™” μ½”λ“œλŠ” init ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ μ΄ˆκΈ°ν™” λΈ”λ‘μ—μ„œ μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

class Init(name: String) {
    init {
        println("First initializer block that prints $name")
    }

    val secondProperty = "Second property: ${name.length}".also(::println)
    
    init {
        println("Second initializer block that prints ${name.length}")
    }
}

fun main() {
    Init("Hello Kotlin")
}

 

 

λ˜ν•œ λ‹€μŒμ²˜λŸΌ μ£Ό μƒμ„±μžμ˜ νŒŒλΌλ―Έν„°λ₯Ό μ΄ˆκΈ°ν™” λΈ”λ‘μ—μ„œ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

class Customer(name: String) {
    val customerKey = name.uppercase()
}

 

코틀린은 μ£Ό μƒμ„±μžμ— 속성듀을 μ„ μ–Έν•˜κ³  μ΄ˆκΈ°ν™”ν•˜λŠ” κ°„κ²°ν•œ 문법을 μ œκ³΅ν•©λ‹ˆλ‹€.

class Person(val firstName: String, val lastName: String, var age: Int)

 

λ˜ν•œ λ‹€μŒκ³Ό 같이 μ£Ό μƒμ„±μžμ—μ„œ λ””ν΄νŠΈ 값을 μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

class Person(val name: String, var isEmployeed: Boolean = true)

 

λ‹€μŒκ³Ό 같이 trailing commaλ₯Ό ν†΅ν•΄μ„œλ„ μ„ μ–Έν•  수 μžˆμŠ΅λ‹ˆλ‹€.

class Person(
    val firstName: String,
    val lastName: String,
    var age: Int
)

 

 

 

Secondary constructors(λΆ€ μƒμ„±μž)


constructor ν‚€μ›Œλ“œλ₯Ό 톡해 λΆ€ μƒμ„±μžλ₯Ό μ„ μ–Έν•  수 μžˆμŠ΅λ‹ˆλ‹€.

class Person(val pets: MutableList<Pet> = mutableListOf())

class Pet {
    constructor(owner: Person) {
        owner.pets.add(this)
    }
}

 

λ§Œμ•½ ν΄λž˜μŠ€μ— μ£Ό μƒμ„±μž(Primary constructor)이 μžˆλŠ” 경우, λΆ€ μƒμ„±μžλŠ” μ§κ°„μ ‘μ μœΌλ‘œ λ‹€λ₯Έ λΆ€μƒμ„±μžλ₯Ό 톡해 μ£Ό μƒμ„±μžμ—κ²Œ μœ„μž„μ„ ν•΄μ•Όν•©λ‹ˆλ‹€. 

λ™μΌν•œ ν΄λž˜μŠ€μ—μ„œ λ‹€λ₯Έ μƒμ„±μžμ— λŒ€ν•œ μœ„μž„μ€ this ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

class Person(val name: String) {
    val children: MutableList<Person> = mutableListOf()
    
    constructor(name: String, parent: Person) : this(name) {
        parent.children.add(this)
    }
}

μœ„ μ½”λ“œμ—μ„œ this(name)을 톡해 μ£Ό μƒμ„±μž(val name: String)에 μœ„μž„μ„ ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

 

 

 

κΈ°λ³Έ μƒμ„±μžλ₯Ό κ³΅κ°œν•˜μ§€ μ•ŠκΈ°λ₯Ό μ›ν•œλ‹€λ©΄, private ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜λ©΄ λ©λ‹ˆλ‹€.

class Kotlin private constructor ()

 

 

β€» JVMμ—μ„œ κΈ°λ³Έ μƒμ„±μžμ˜ λͺ¨λ“  λ§€κ°œλ³€μˆ˜μ— 기본값이 μžˆλŠ” 경우, μ»΄νŒŒμΌλŸ¬λŠ” μΆ”κ°€μ μœΌλ‘œ νŒŒλΌλ―Έν„°κ°€ μ—†λŠ”(λ””ν΄νŠΈ) μƒμ„±μžλ₯Ό μƒμ„±ν•©λ‹ˆλ‹€. μ΄λŸ¬ν•œ 방식은 λ§€κ°œλ³€μˆ˜κ°€ μ—†λŠ” μƒμ„±μžλ₯Ό 톡해 객체λ₯Ό μƒμ„±ν•˜λŠ” JPAλ‚˜ Jackson와 같은 λΌμ΄λΈŒλŸ¬λ¦¬μ™€ ν•¨κ»˜ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

class Customer(val name: String = "", val age: Int = 0)

 

 

 

Creating instances of classes


이제 μ½”ν‹€λ¦°μ—μ„œ 객체λ₯Ό μƒμ„±ν•˜λŠ” 방법에 λŒ€ν•΄ μ‚΄νŽ΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

κΈ°μ‘΄ μžλ°”μ™€λŠ” λ‹€λ₯΄κ²Œ μ½”ν‹€λ¦°μ—μ„œλŠ” new ν‚€μ›Œλ“œκ°€ μ‘΄μž¬ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

이 뢀뢄도 μ €λŠ” 처음 μ‚¬μš©ν• λ•Œ μ•½κ°„ ν—·κ°ˆλ¦¬λŠ” λΆ€λΆ„μ΄μ—ˆμŠ΅λ‹ˆλ‹€.

class Customer(var name: String = "", var age: Int = 0) {

    override fun toString(): String {
        return "Customer(name='$name', age=$age)"
    }
}

fun main() {
    val noArgCustomer = Customer()
    val argsCustomer = Customer("JuHyun", 20)

    println(noArgCustomer)
    println(argsCustomer)
}

 

 

 

Inheritance(상속)


μ½”ν‹€λ¦°μ—μ„œμ˜ μƒμ†λ˜ν•œ μžλ°”μ™€ μ•½κ°„ λ‹€λ¦…λ‹ˆλ‹€. μžλ°”μ—μ„œ μ΅œμƒμœ„ ν΄λž˜μŠ€λŠ” Objectμ΄μ§€λ§Œ, μ½”ν‹€λ¦°μ—μ„œλŠ” AnyλΌλŠ” ν΄λž˜μŠ€μž…λ‹ˆλ‹€.

μ½”ν‹€λ¦°μ—μ„œλŠ” 기본적으둜 ν΄λž˜μŠ€κ°€ final이기 λ•Œλ¬Έμ— 상속을 ν•  수 μ—†μŠ΅λ‹ˆλ‹€. λ”°λΌμ„œ 상속을 κ°€λŠ₯ν•˜κ²Œ ν•˜λ €λ©΄ open ν‚€μ›Œλ“œλ₯Ό μ„ μ–Έν•΄μ•Ό ν•©λ‹ˆλ‹€.

open class Parent(var name: String) 

class child(var names: String) : Parent(names)

 

λ§Œμ•½ λΆ€λͺ¨ ν΄λž˜μŠ€μ— open ν‚€μ›Œλ“œλ₯Ό μ„ μ–Έν•˜μ§€ μ•ŠλŠ”λ‹€λ©΄ μ•„λž˜μ²˜λŸΌ 컴파일 μ—λŸ¬κ°€ λ°œμƒν•©λ‹ˆλ‹€.

 

 

 

Abstract classes(좔상 클래슀)


좔상 ν΄λž˜μŠ€λŠ” μžλ°”μ™€ λ™μΌν•˜κ²Œ abstract ν‚€μ›Œλ“œλ₯Ό μ„ μ–Έν•˜λ©΄ λ©λ‹ˆλ‹€. λ˜ν•œ 좔상 클래슀λ₯Ό μƒμ†ν• κ²½μš° open ν‚€μ›Œλ“œλ₯Ό μ„ μ–Έν•˜μ§€ μ•Šμ•„λ„ 컴파일 μ—λŸ¬κ°€ λ°œμƒν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

abstract class Polygon {
    abstract fun draw()
}

class Rectangle : Polygon() {
    override fun draw() {
    }
}

 

 

 

Companion Object


 

μ½”ν‹€λ¦°μ—μ„œλŠ” μžλ°”μ˜ static이 μ—†λŠ”λŒ€μ‹  Companion Objectλ₯Ό μ‚¬μš©ν•΄ 블둝{} μ•ˆμ— 멀버λ₯Ό κ΅¬μ„±ν•©λ‹ˆλ‹€.

즉, 클래슀 μΈμŠ€ν„΄μŠ€ 없이 ν˜ΈμΆœν•  수 μžˆλŠ”μ •μ  νŒ©ν„°λ¦¬ λ©”μ†Œλ“œλ₯Ό μ˜λ―Έν•©λ‹ˆλ‹€.

data class ErrorResponse(
        val message: String? = null,
        val errors: MutableList<Error>? = mutableListOf()
) {
    private constructor(message: String) : this(message, null)

    companion object {
        fun of(message: String?) = of(message, null)
        fun of(message: String?, errors: MutableList<Error>?) = ErrorResponse(message, errors)
    }
}

fun main() {
    val errorResponse = ErrorResponse.Companion.of("message")
    val errorResponse2 = ErrorResponse.Companion.of("message", null)
}

μœ„μ™€ 같이 companion object ν‚€μ›Œλ“œλ₯Ό 톡해 2개의 of λ©”μ†Œλ“œλ₯Ό μ„ μ–Έν•˜κ³ , main λ©”μ†Œλ“œμ—μ„œ 클래슀λͺ….Companion.λ©”μ†Œλ“œλͺ… 으둜 접근을 ν•  수 μžˆμŠ΅λ‹ˆλ‹€. (Companion은 μƒλž΅μ΄ κ°€λŠ₯ν•©λ‹ˆλ‹€.)

 

 

β€» 그럼 Companion Object와 static이 λ™μΌν•œκ°€μš”?

  -> κ·Έλ ‡μ§€λŠ” μ•ŠμŠ΅λ‹ˆλ‹€. Companion Object의 경우 κ°μ²΄μΈλ°μš”, μ•„λž˜ μ½”λ“œλ₯Ό μ‚΄νŽ΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

 

companion objectλŠ” 객체이닀.

class MyClass {

    companion object {
        val message = "Companion Object message"
        fun com() = "com method"
    }
}

fun main() {
    // 1) companion objectλŠ” κ°μ²΄μ΄λ―€λ‘œ λ³€μˆ˜μ— 할당이 κ°€λŠ₯
    val com1 = MyClass.Companion
    println(com1.message)
    println(com1.com())

    // 2)
    val com2 = MyClass
    println(com2.message)
    println(com2.com())
}

1) μœ„ com1 λ³€μˆ˜λŠ” MyClass의 Companion으둜 할당이 κ°€λŠ₯ν•©λ‹ˆλ‹€. 

κ·Έ ν›„ com1λ³€μˆ˜μ— 점(.)으둜 companion object의 멀버듀에 접근을 ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 이처럼 λ³€μˆ˜μ— ν• λ‹Ήν•˜λŠ” 것은 μžλ°”μ˜ ν΄λž˜μŠ€μ—μ„œ static ν‚€μ›Œλ“œλ‘œ μ •μ˜λœ λ©€λ²„λ‘œλŠ” λΆˆκ°€λŠ₯ν•œ λ°©λ²•μž…λ‹ˆλ‹€.

 

2) 두 번째 com2 λ³€μˆ˜λŠ” .Companion을 μ œμ™Έν•˜κ³  직접 MyClass둜 할당을 ν–ˆμŠ΅λ‹ˆλ‹€. μ΄κ²ƒλ˜ν•œ companion objectμ΄λ―€λ‘œ ν•΄λ‹Ή 멀버듀에 접근을 ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 즉, κΈ°μ–΅ν•΄μ•Ό ν•  점은 클래슀 λ‚΄ μ •μ˜λœ companion objectλŠ” 클래슀 μ΄λ¦„λ§ŒμœΌλ‘œλ„ μ°Έμ‘°κ°€ κ°€λŠ₯ν•˜λ‹€λŠ” μ μž…λ‹ˆλ‹€. 

μžλ°”μ—μ„œμ˜ static ν‚€μ›Œλ“œλŠ” μ½”ν‹€λ¦°μ˜ companion objectμ™€λŠ” 달리 ν•˜λ‚˜μ˜ λ…λ¦½λœ 객체둜 μ—¬κ²¨μ§ˆ 수 μ—†κΈ° λ•Œλ¬Έμ—, 차이점이 μžˆμŠ΅λ‹ˆλ‹€.

 

 

companion objectλŠ” 이름을 μ„ μ–Έν•  수 μžˆλ‹€.

class MyClass {

    companion object Info {
        val message = "Companion Object message"
        fun com() = "com method"
    }
}

fun main() {
    println(MyClass.Info.message)
    println(MyClass.message)
}

 

companion object에 λŒ€ν•΄ μΆ”κ°€μ μœΌλ‘œ κΆκΈˆν•˜μ‹  뢄은 μ•„λž˜ 글에 μ„€λͺ…이 μž˜λ˜μ–΄μžˆμœΌλ‹ˆ μ°Έκ³ ν•΄μ£Όμ„Έμš” :)

 

 

정리

κ·Έλ™μ•ˆ 코틀린은 κ³΅μ‹λ¬Έμ„œκ°€ 정말 μž˜λ˜μ–΄μžˆμ–΄μ„œ κ³΅μ‹λ¬Έμ„œλ§Œ 봐도 μΆ©λΆ„ν•˜λ‹€λŠ” 글을 λͺ‡λͺ‡λ΄€μ—ˆλŠ”λ°μš”, μ΄λ²ˆμ— μ½”ν‹€λ¦° κ³΅μ‹λ¬Έμ„œλ₯Ό λ³΄λ©΄μ„œ λ‹€λ₯Έ 뢄듀이 ν•˜μ‹  말씀이 μ™€λ‹Ώμ•˜μŠ΅λ‹ˆλ‹€. μ§€λ‚œλ²ˆ μ½”ν‹€λ¦°μ˜ μƒμ„±μž, 상속 κ΄€λ ¨ν•΄μ„œ μžλ°”μ˜ λ¬Έλ²•κ³ΌλŠ” κ½€ λ‹¬λΌμ„œ μ•½κ°„ 고생을 ν–ˆμ—ˆλŠ”λ°μš”(?) λ§Œμ•½ κ·Έλ•Œ ꡬ글링이 μ•„λ‹Œ κ³΅μ‹λ¬Έμ„œλ₯Ό λ°”λ‘œ ν™•μΈν–ˆλ”λΌλ©΄, 훨씬 더 λΉ λ₯΄κ²Œ 문제λ₯Ό ν•΄κ²°ν•  수 μžˆμ—ˆμ„ 것 κ°™μŠ΅λ‹ˆλ‹€.

 

아직 코틀린이 μ΅μˆ™ν•˜μ§€ μ•ŠκΈ°λ•Œλ¬Έμ— 코틀린을 μ½”ν‹€λ¦°λ‹΅κ²Œ μ‚¬μš©ν•˜μ§€ λͺ»ν•˜κ³  μžˆλŠ”λ°μš”, μ•„λ¬΄λž˜λ„ 점점 μ‚¬μš©ν•˜κ³  λ§Žμ€ μ½”λ“œλ₯Ό μ ‘ν•˜λ‹€λ³΄λ©΄ 코틀린을 μ½”ν‹€λ¦°λ‹΅κ²Œ μ‚¬μš©ν•˜λŠ” 날이 μ˜€μ§€μ•Šμ„κΉŒ ν•©λ‹ˆλ‹€.. πŸ˜ƒ

 

 

β€» μ•„λž˜ μ˜μƒμ€ 코틀린에 λŒ€ν•΄ μ—¬λŸ¬ νŒλ“€μ„ μ „μˆ˜ν•΄μ£Όμ‹œκΈ° λ•Œλ¬Έμ— ν˜Ήμ‹œ μ‹œκ°„μ΄ λ˜μ‹ λ‹€λ©΄ κ°•λ ₯μΆ”μ²œ λ“œλ¦½λ‹ˆλ‹€ :)

https://www.youtube.com/watch?v=ewBri47JWII 

 

 

λ°˜μ‘ν˜•

λŒ“κΈ€