๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

๋นˆ ๊ตฌ๋ฉ ์ฑ„์šฐ๊ธฐ

[Kotlin] init ๋ธ”๋ก

์ถœ์ฒ˜

https://kotlinlang.org/docs/classes.html#constructors

 

Classes | Kotlin

 

kotlinlang.org

https://kotlinlang.org/docs/inheritance.html#derived-class-initialization-order

 

Inheritance | Kotlin

 

kotlinlang.org

 

 


ํด๋ž˜์Šค์˜ ์ดˆ๊ธฐํ™”

๊ธฐ๋ณธ ์ƒ์„ฑ์ž๋Š” ํด๋ž˜์Šค ํ—ค๋”(ํด๋ž˜์Šค์˜ ์ด๋ฆ„๊ณผ ์ฃผ์ƒ์„ฑ์ž)์—์„œ ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค์™€ ํ•ด๋‹น ์†์„ฑ์„ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค. ๊ฐ์ฒด ์ƒ์„ฑ ์ค‘์— ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ ค๋ฉด ํด๋ž˜์Šค ๋ณธ๋ฌธ ๋‚ด๋ถ€์— ์ดˆ๊ธฐํ™” ๋ธ”๋ก์„ ์‚ฌ์šฉํ•œ๋‹ค. ์ดˆ๊ธฐํ™” ๋ธ”๋ก์€ init ํ‚ค์›Œ๋“œ ๋’ค์— ์ค‘๊ด„ํ˜ธ๋ฅผ ๋ถ™์—ฌ ์„ ์–ธํ•œ๋‹ค. ์‹คํ–‰ํ•˜๋ ค๋Š” ์ฝ”๋“œ๋Š” ์ค‘๊ด„ํ˜ธ ์•ˆ์— ์ž‘์„ฑํ•œ๋‹ค.

 

์ธ์Šคํ„ด์Šค๋ฅผ ์ดˆ๊ธฐํ™” ์ค‘์— ์ดˆ๊ธฐํ™” ๋ธ”๋ก๊ณผ ์†์„ฑ ์ดˆ๊ธฐํ™”๋Š” ํด๋ž˜์Šค ์•ˆ์— ๊ธฐ์ž…๋œ ์ˆœ์„œ(์œ„์—์„œ ์•„๋ž˜)๋กœ ์‹คํ–‰๋œ๋‹ค. 

class InitOrderDemo(name: String) {
    val firstProperty = "First property: $name".also(::println)
    
    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() {
    InitOrderDemo("hello")
}

// (์ถœ๋ ฅ ๊ฒฐ๊ณผ)
// First property: hello
// First initializer block that prints hello
// Second property: 5
// Second initializer block that prints 5

 

๋ถ€ ์ƒ์„ฑ์ž

ํด๋ž˜์Šค๋Š” constructor ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ๋ถ€ ์ƒ์„ฑ์ž๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค. 

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

class Pet {
    constructor(owner: Person) {
        owner.pets.add(this) // adds this pet to the list of its owner's pets
    }
}

 

 

ํด๋ž˜์Šค์— ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ, ๊ฐ ๋ณด์กฐ ์ƒ์„ฑ์ž๋Š” ๊ธฐ๋ณธ ์ƒ์„ฑ์ž์—๊ฒŒ ์ง์ ‘ ์œ„์ž„ํ•˜๊ฑฐ๋‚˜, ๋‹ค๋ฅธ ๋ณด์กฐ ์ƒ์„ฑ์ž๋“ค๋กœ ๊ฐ„์ ‘์ ์œผ๋กœ ์ƒ์„ฑ์„ ์œ„์ž„ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋‹ค๋ฅธ ์ƒ์„ฑ์ž์—๊ฒŒ ์œ„์ž„ํ•  ๋•Œ this ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

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

 

 

์ดˆ๊ธฐํ™” ์ฝ”๋“œ๋Š” ๊ธฐ๋ณธ ์ƒ์„ฑ์ž์˜ ์ผ๋ถ€๊ฐ€ ๋œ๋‹ค. ๊ธฐ๋ณธ ์ƒ์„ฑ์ž์— ์œ„์ž„ํ•˜๋Š” ๊ฒƒ์ด ๋ถ€ ์ƒ์„ฑ์ž์˜ ์ฒซ์งธ ๋ฌธ์ž์— ์ ‘๊ทผํ•˜๋Š” ๋•Œ์— ์ผ์–ด๋‚˜์„œ , ๋ถ€ ์ƒ์„ฑ์ž์˜ ์ฝ”๋“œ ๋ธ”๋ก์€ ๋ชจ๋“  init ๋ธ”๋ก๊ณผ ์ƒ์„ฑ์ž ์ดˆ๊ธฐํ™”๊ฐ€ ๋‹ค ์‹คํ–‰๋œ ํ›„์— ์‹คํ–‰๋œ๋‹ค. 

 

ํด๋ž˜์Šค์— ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๊ฐ€ ์—†๋”๋ผ๋„, ์œ„์ž„์€ ์•”๋ฌต์ ์œผ๋กœ ๋ฐœ์ƒํ•ด์„œ ์ดˆ๊ธฐํ™” ๋ธ”๋ก์ด ๊ณ„์† ์‹คํ–‰๋œ๋‹ค.

class Constructors {
    init {
        println("Init block")
    }

    constructor(i: Int) {
        println("Constructor $i")
    }
}
// (์ถœ๋ ฅ ๊ฒฐ๊ณผ) 
// Init block
// Constructor 1

 

ํด๋ž˜์Šค ์ƒ์†์˜ ๊ฒฝ์šฐ init ๋ธ”๋ก์˜ ์‹คํ–‰

์ž์‹ ํด๋ž˜์Šค๊ฐ€ ์ƒˆ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„œํ•˜๋Š” ๋™์•ˆ ๋ถ€๋ชจ ํด๋ž˜์Šค์˜ ์ดˆ๊ธฐํ™”๊ฐ€ ๋งจ ๋จผ์ € ์ˆ˜ํ–‰๋œ๋‹ค. ๊ทธ ํ›„์— ์ž์‹ ํด๋ž˜์Šค์˜ ์ดˆ๊ธฐํ™”๊ฐ€ ์ง„ํ–‰๋œ๋‹ค.

open class Base(val name: String) {

    init { println("Initializing a base class") }

    open val size: Int = 
        name.length.also { println("Initializing size in the base class: $it") }
}

class Derived(
    name: String,
    val lastName: String,
) : Base(name.replaceFirstChar { it.uppercase() }.also { println("Argument for the base class: $it") }) {

    init { println("Initializing a derived class") }

    override val size: Int =
        (super.size + lastName.length).also { println("Initializing size in the derived class: $it") }
}

fun main() {
    println("Constructing the derived class(\"hello\", \"world\")")
    Derived("hello", "world")
}
// (์ถœ๋ ฅ ๊ฒฐ๊ณผ)
// Constructing the derived class("hello", "world")
// Argument for the base class: Hello
// Initializing a base class
// Initializing size in the base class: 5
// Initializing a derived class
// Initializing size in the derived class: 10

 

๋ถ€๋ชจ ํด๋ž˜์Šค๊ฐ€ ์ƒ์„ฑ์ž๊ฐ€ ์‹คํ–‰๋  ๋Œ€, ์ž์‹ ํด๋ž˜์Šค์—์„œ ์„ ์–ธ๋˜๊ฑฐ๋‚˜ ์˜ค๋ฒ„๋ผ์ด๋“œ๋œ ํ”„๋กœํผํ‹ฐ๋Š” ์•„์ง ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š์€ ์ƒํƒœ์ด๋‹ค. ๋ถ€๋ชจ ํด๋ž˜์Šค ์ดˆ๊ธฐํ™”์—์„œ ์•„์ง ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š์€ ์ž์‹ ํด๋ž˜์Šค์˜ ํ”„๋กœํผํ‹ฐ๋“ค์„ ์‚ฌ์šฉํ•˜๋ฉด ์ž˜๋ชป๋œ ๋™์ž‘์ด๋‚˜ ๋Ÿฐํ„ฐ์ž„ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋ถ€๋ชจ ํด๋ž˜์Šค๋ฅผ ์„ค๊ณ„ํ•  ๋•Œ์—๋Š” ์ƒ์„ฑ์ž์˜ open ํ”„๋กœํผํ‹ฐ, ํ”„๋กœํผํ‹ฐ ์ดˆ๊ธฐํ™” ์ž‘์—…, init ๋ธ”๋ก์€ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋„๋ก ํ”ผํ•ด์•ผ ํ•œ๋‹ค. 

 

ํด๋ž˜์Šค ๋ถ€ ์ƒ์„ฑ์ž์˜ init ๋ธ”๋ก ์‹คํ–‰ ์ˆœ์„œ ํ™•์ธํ•˜๊ธฐ

1. ์ฃผ ์ƒ์„ฑ์ž๋กœ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ. ํด๋ž˜์Šค ์•ˆ์— ์—ฌ๋Ÿฌ init ๋ธ”๋ก์ด ์žˆ๋Š” ๊ฒฝ์šฐ

class Person(val name: String, val age: Int){ // -> ํ˜ธ์ถœ. ์ฃผ ์ƒ์„ฑ์ž๋กœ ๊ฐ์ฒด ์ƒ์„ฑ

    init { // -> ์‹คํ–‰ 1
        println("primary constructor : $name, $age")
    }

    constructor() : this(name= "none", age= 0) {
        println("secondary constructor $name, $age")
    }

    constructor(message: String) : this() {
        println("secondary constructor 2 : $name, $age")
    }

    init { // -> ์‹คํ–‰ 2
        println("primary constructor 2 : $name, $age")
    }

}

fun main() {
    Person("Alice", 29)
}

// (์ถœ๋ ฅ ๊ฒฐ๊ณผ)
// primary constructor : Alice, 29
// primary constructor 2 : Alice, 29

 

  1. ํด๋ž˜์Šค ๋‚ด๋ถ€์— ์œ„์—์„œ๋ถ€ํ„ฐ ์•„๋ž˜ ์ˆœ์„œ๋กœ ์„ ์–ธ๋œ init ๋ธ”๋ก์„ ์‹คํ–‰ํ•œ๋‹ค.

 

2. ๋ถ€ ์ƒ์„ฑ์ž๋กœ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š”๋ฐ, ๊ฐ์ฒด ์ƒ์„ฑ์„ ์ฃผ ์ƒ์„ฑ์ž์— ์œ„์ž„ํ•œ๋‹ค.  ํ˜ธ์ถœํ•˜๋Š” ๋ถ€์ƒ์„ฑ์ž๋Š” ์ฝ”๋“œ ๋ธ”๋ก์œผ๋กœ ๋ถ€ ์ƒ์„ฑ์ž์˜ init ๋ธ”๋ก์„ ์„ ์–ธํ–ˆ๋‹ค.

class Person(val name: String, val age: Int){ 

    init { // -> ์‹คํ–‰ 1
        println("primary constructor : $name, $age")
    }

    constructor() : this(name= "none", age= 0) {  // -> ํ˜ธ์ถœ. ์ฃผ ์ƒ์„ฑ์ž์—๊ฒŒ ๊ฐ์ฒด ์ƒ์„ฑ ์œ„์ž„
        println("secondary constructor $name, $age") // -> ์‹คํ–‰ 3
    }

    constructor(message: String) : this() {
        println("secondary constructor 2 : $name, $age")
    }

    init { // -> ์‹คํ–‰ 2
        println("primary constructor 2 : $name, $age")
    }

}

fun main() {
    Person()
}

// (์ถœ๋ ฅ ๊ฒฐ๊ณผ)
// primary constructor : none, 0
// primary constructor 2 : none, 0
// secondary constructor none, 0

 

  1. ๋จผ์ € ์ฃผ ์ƒ์„ฑ์ž๋กœ ํ˜ธ์ถœํ•˜๋Š” ๊ฐ์ฒด ์ดˆ๊ธฐํ™” ๋ฃจํŠธ๋ฅผ ํƒ„๋‹ค. ํด๋ž˜์Šค์˜ ์œ„์—์„œ ์•„๋ž˜๋กœ๋ถ€ํ„ฐ ์„ ์–ธ๋œ init ๋ธ”๋ก์„ ์‹คํ–‰ํ•œ๋‹ค.
  2. ๊ทธ ๋‹ค์Œ ํ˜ธ์ถœํ•œ ๋ถ€ ์ƒ์„ฑ์ž์˜ ์ฝ”๋“œ ๋ธ”๋ก์„ ์‹คํ–‰ํ•œ๋‹ค.

 

2. ๋ถ€ ์ƒ์„ฑ์ž๋กœ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š”๋ฐ, ๊ฐ์ฒด ์ƒ์„ฑ์„ ๋‹ค๋ฅธ ๋ถ€ ์ƒ์„ฑ์ž์— ์œ„์ž„ํ•œ๋‹ค.  ํ˜ธ์ถœํ•˜๋Š” ๋ถ€์ƒ์„ฑ์ž๋Š” ์ฝ”๋“œ ๋ธ”๋ก์œผ๋กœ ๋ถ€ ์ƒ์„ฑ์ž์˜ init ๋ธ”๋ก์„ ์„ ์–ธํ–ˆ๋‹ค.

class Person(val name: String, val age: Int){ 

    init { // -> ์‹คํ–‰ 1
        println("primary constructor : $name, $age")
    }

    constructor() : this(name= "none", age= 0) { 
        println("secondary constructor $name, $age") // -> ์‹คํ–‰ 3
    }

    constructor(message: String) : this() { // -> ํ˜ธ์ถœ. ๋‹ค๋ฅธ ๋ถ€ ์ƒ์„ฑ์ž์—๊ฒŒ ๊ฐ์ฒด ์ƒ์„ฑ ์œ„์ž„
        println("secondary constructor 2 : $name, $age") // -> ์‹คํ–‰ 4
    }

    init { // -> ์‹คํ–‰ 2
        println("primary constructor 2 : $name, $age")
    }

}

fun main() {
    Person("Hello World")
}

// (์ถœ๋ ฅ ๊ฒฐ๊ณผ)
// primary constructor : none, 0
// primary constructor 2 : none, 0
// secondary constructor none, 0
// secondary constructor 2 : none, 0
  1. ๋จผ์ € ์ฃผ ์ƒ์„ฑ์ž๋กœ ํ˜ธ์ถœํ•˜๋Š” ๊ฐ์ฒด ์ดˆ๊ธฐํ™” ๋ฃจํŠธ๋ฅผ ํƒ„๋‹ค. ํด๋ž˜์Šค์˜ ์œ„์—์„œ ์•„๋ž˜๋กœ๋ถ€ํ„ฐ ์„ ์–ธ๋œ init ๋ธ”๋ก์„ ์‹คํ–‰ํ•œ๋‹ค.
  2. ๊ทธ ๋‹ค์Œ ๊ฐ์ฒด ์ƒ์„ฑ์„ ์œ„์ž„ํ•œ ๋ถ€ ์ƒ์„ฑ์ž์˜ ์ฝ”๋“œ ๋ธ”๋ก์„ ์‹คํ–‰ํ•œ๋‹ค.
  3. ๋งˆ์ง€๋ง‰์œผ๋กœ ํ˜ธ์ถœํ•œ ๋ถ€ ์ƒ์„ฑ์ž์˜ ์ฝ”๋“œ ๋ธ”๋ก์„ ์‹คํ–‰ํ•œ๋‹ค.