๊นจ์•Œ ๊ฐœ๋… ๐Ÿ“‘/Kotlin

[Kotlin] ํ”„๋กœํผํ‹ฐ(Property)

interfacer_han 2024. 1. 17. 11:20

#1 ํ•„๋“œ์™€ ํ”„๋กœํผํ‹ฐ

#1-1 ํ”„๋กœํผํ‹ฐ์˜ ๊ฐœ๋…

// Java
String name = "steve"; // Field

System.out.println("my name is" + name);
name = "kevin";

---

// Kotlin
var name : String = "steve" // Property

println("my name is" + name)
name = "kevin"

์ฝ”ํ‹€๋ฆฐ์—๋Š” ํ•„๋“œ์˜ ์—ญํ• ์„ ํ”„๋กœํผํ‹ฐ(์†์„ฑ)๊ฐ€ ์ˆ˜ํ–‰ํ•œ๋‹ค. ํ•„๋“œ๋Š” ๊ฐ’ ๊ทธ๋ฆฌ๊ณ  ๊ทธ ๊ฐ’์— ์ ‘๊ทผํ•˜๋Š” ๋ ˆํผ๋Ÿฐ์Šค์˜ ๋‹จ์ˆœํ•œ ๊ตฌ์„ฑ์ด๋‹ค. ํ”„๋กœํผํ‹ฐ๋Š” ์—ฌ๊ธฐ์— ๊ทธ ๊ฐ’์„ ๋‹ค๋ฃจ๋Š” ๋ฉ”์†Œ๋“œ ์ฆ‰, Getter์™€ Setter๋ฅผ ๊ฒฐํ•ฉํ•œ ๊ฐœ๋…์ด๋‹ค. ํ•˜์ง€๋งŒ, ์œ„ ์ฝ”๋“œ์—์„œ ์ž๋ฐ”์˜ ํ•„๋“œ name๊ณผ ์ฝ”ํ‹€๋ฆฐ์˜ ํ”„๋กœํผํ‹ฐ name์€ ์„œ๋กœ ๋‹ค๋ฅธ ๊ฒŒ ์—†์–ด๋ณด์ธ๋‹ค. ์ด๋Š” ํ”„๋กœํผํ‹ฐ๊ฐ€ ๋ณด์œ ํ•œ Getter์™€ Setter๊ฐ€ ์ƒ๋žต๋˜์–ด์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ƒ๋žต๋œ ๋ถ€๋ถ„์„ ๋ช…์‹œ์ ์œผ๋กœ ๋ฐํ˜€์“ฐ๋ฉด ์•„๋ž˜๊ณผ ๊ฐ™๋‹ค.
 

#1-2 ๋ช…์‹œ์  get() ๋ฐ set()

// Java
String name = "steve"; // Field

System.out.println("my name is" + name);
name = "kevin";

---

// Kotlin
var name : String = "steve" // Property
    get() = field
    set(value) {
        field = value
    }

println("my name is" + name) // println("my name is" + name.get())
name = "kevin" // name.set("kevin")

๋จผ์ €, field๋ผ๋Š” ์ด๋ฆ„์˜ ํ‚ค์›Œ๋“œ๋ถ€ํ„ฐ ์„ค๋ช…ํ•œ๋‹ค. ์ด field๋Š” ์šฐ๋ฆฌ๊ฐ€ ์•„๋Š” ์ „ํ†ต์ ์ธ ์˜๋ฏธ์˜ ํ•„๋“œ๊ฐ€ ์•„๋‹ˆ๋ฉฐ, Backing Field๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ๋ถˆ๋ฆฐ๋‹ค. ๋ฐฑํ‚น ํ•„๋“œ๋Š” ์ž์ฒด์ ์œผ๋กœ ์กด์žฌํ•  ์ˆ˜ ์—†๊ณ , ์˜ค์ง ํ”„๋กœํผํ‹ฐ์˜ ๊ฐ’์„ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•ด ์กด์žฌํ•˜๋Š”, ํ”„๋กœํผํ‹ฐ์— ์ข…์†๋œ ์ €์žฅ์†Œ๋‹ค. value๋Š” field์ฒ˜๋Ÿผ ์ฝ”ํ‹€๋ฆฐ์˜ ํ‚ค์›Œ๋“œ๋Š” ์•„๋‹ˆ๊ณ  ๊ทธ๋ƒฅ ๋งค๊ฐœ๋ณ€์ˆ˜๋‹ค. v ๋ผ๋“ ์ง€ argument ๋ผ๋“ ์ง€๋กœ ๊ณ ์ณ์จ๋„ ๋œ๋‹ค.

์ฝ”ํ‹€๋ฆฐ์—์„œ ๋ณ€์ˆ˜ name์— ๊ฐ’์„ ์ฐธ์กฐํ•˜๊ฑฐ๋‚˜ ์žฌํ• ๋‹นํ•  ๋•Œ ๊ฐ๊ฐ Getter์™€ Setter์˜ ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•˜๋Š” name.get()๊ณผ name.set()๋ผ๋Š” ๋ฉ”์†Œ๋“œ๊ฐ€ ์ž๋™์œผ๋กœ ํ˜ธ์ถœ๋œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜, name.get()์ด๋‚˜ name.set() ๋ฉ”์†Œ๋“œ๋ฅผ ์•„๋ž˜ ์ชฝ ์ฝ”๋“œ์— ๋ถ™์–ด ์žˆ๋Š” ์ฃผ์„๋“ค์ฒ˜๋Ÿผ ๋ช…์‹œ์ ์œผ๋กœ ์“ธ ์ˆ˜ ์žˆ๋Š” ๊ฑด ์•„๋‹ˆ๋‹ค. Getter์™€ Setter์˜ ๋™์ž‘์€ ๊ทธ์ € ํ”„๋กœํผํ‹ฐ๋ช…(๋ ˆํผ๋Ÿฐ์Šค)๋ฅผ ํ˜ธ์ถœํ•˜๊ฑฐ๋‚˜ ํ”„๋กœํผํ‹ฐ๋ช…์— ๋Œ€์ž…ํ•  ๋•Œ ์•Œ์•„์„œ ์ˆ˜ํ–‰๋  ๋ฟ์ด๋‹ค.
 
get() ๋˜๋Š” set()์„ ํ”„๋กœ๊ทธ๋ž˜๋จธ์˜ ์ž…๋ง›๋Œ€๋กœ ์ปค์Šคํ…€ํ•˜์ง€ ์•Š๋Š” ์ด์ƒ get()๊ณผ set()์„ ๋ช…์‹œ์ ์œผ๋กœ ๋ณผ ์ผ์€ ์—†๋‹ค. ๋‹ค์Œ ์ฝ”๋“œ์—์„œ ํ•œ๋ฒˆ get()๊ณผ set()์„ ์ž…๋ง›๋Œ€๋กœ ์ปค์Šคํ…€ํ•ด๋ณด๊ฒ ๋‹ค.
 

#1-3 Getter์™€ Setter ์ปค์Šคํ…€ํ•˜๊ธฐ, var ํ”„๋กœํผํ‹ฐ์™€ val ํ”„๋กœํผํ‹ฐ์˜ ์ฐจ์ด

class PropertyPractice1 {
    var name : String = "steve"
        get() {
            return field[0].uppercase() + field.substring(1) // ์ด๋ฆ„ ์ฒซ ๊ธ€์ž๋ฅผ ๋Œ€๋ฌธ์ž๋กœ
        }
        set(value) {
            field = value.replace(" ", "") // ๋ชจ๋“  ๊ณต๋ฐฑ ์ œ๊ฑฐ
        }
}

fun main() {
    val instance = PropertyPractice1()

    println("my name is " + instance.name)
    instance.name = "k e v i n"
    println("my name is " + instance.name)
}

/* ์‹คํ–‰ ๊ฒฐ๊ณผ:
 * my name is Steve
 * my name is Kevin
 */

PropertyPractice1.name๊ณผ ๊ฐ™์€ var ํ”„๋กœํผํ‹ฐ๋Š” get()๊ณผ set() ๋‘˜ ๋‹ค ๋ณด์œ ํ•˜๊ณ  ์žˆ๋‹ค. ๋ฐ˜๋ฉด, val ํ”„๋กœํผํ‹ฐ๋Š” get()๋งŒ์„ ๋ณด์œ ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ, ๋งŒ์•ฝ ์œ„์˜ ์ฝ”๋“œ์—์„œ name ํ”„๋กœํผํ‹ฐ๊ฐ€ val์ด์—ˆ๋‹ค๋ฉด set() ๋ถ€๋ถ„์€ ์กด์žฌํ•  ์ˆ˜ ์—†๋‹ค.
 

#2 private ํ”„๋กœํผํ‹ฐ์— ์ ‘๊ทผํ•˜๊ธฐ

class PropertyPractice2 {
    private var name : String = "steve"
        get() {
            return field[0].uppercase() + field.substring(1) // ์ด๋ฆ„ ์ฒซ ๊ธ€์ž๋ฅผ ๋Œ€๋ฌธ์ž๋กœ
        }
        set(value) {
            field = value.replace(" ", "") // ๋ชจ๋“  ๊ณต๋ฐฑ ์ œ๊ฑฐ
        }

    val nameData : String
        get() = name
}

fun main() {
    val instance = PropertyPractice2()

    // ↓ Error
    // println("my name is " + instance.name)
    
    // ↓ ์ •์ƒ ์ž‘๋™
    println("my name is " + instance.nameData)
}

/* ์‹คํ–‰ ๊ฒฐ๊ณผ:
 * my name is Steve
 */

์ž๋ฐ”์—์„  Getter์™€ Setter์— public ์ ‘๊ทผ์ œ์–ด์ž๋ฅผ ๋ถ™์—ฌ์„œ, privateํ•œ ํ•„๋“œ๋ฅผ ์ฐธ์กฐํ•˜๊ฑฐ๋‚˜ ์žฌ์„ค์ •ํ•  ๋•Œ ์“ฐ๊ณค ํ–ˆ๋‹ค. ์ฝ”ํ‹€๋ฆฐ์—์„œ๋„ ํ”„๋กœํผํ‹ฐ ์™ธ๋ถ€์˜ ๋ฉ”์†Œ๋“œ, ์˜ˆ๋ฅผ๋“ค์–ด getName()์„ ๋งŒ๋“ค์–ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๋•Œ, ์ฝ”ํ‹€๋ฆฐ์—์„œ๋Š” ๋ฉ”์†Œ๋“œ๊ฐ€ ์•„๋‹Œ ํ”„๋กœํผํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ๋ฐ”๋กœ, ๋‹ค๋ฅธ public ํ”„๋กœํผํ‹ฐ์˜ get()์ด privateํ•œ ์ž์‹ ์˜ get()์„ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ๋งŒ๋“ค๋ฉด ๋œ๋‹ค.
 

#3 ๋ฐฑํ‚น ํ•„๋“œ(Backing Field)์˜ ๋ถ€์žฌ(Absence) ์ดํ•ดํ•˜๊ธฐ

var name : String = "steve" // error
    get() {
        return ""
    }
    set(value) {
        return
    }

#1-2์— ์žˆ๋Š” PropertyPractice1 ํด๋ž˜์Šค์˜ name ํ”„๋กœํผํ‹ฐ๋ฅผ ์œ„์™€ ๊ฐ™์ด ๊ณ ์น˜๋ฉด, ๋ฌด์Šจ ์ผ์ด ์ผ์–ด๋‚ ๊นŒ? ๋ฐ”๋กœ, "Initializer is not allowed here because this property has no backing field"๋ผ๋Š” ์—๋Ÿฌ๋ฅผ ๋ฑ‰๋Š”๋‹ค. ํ•ด์„ํ•˜๋ฉด, "์ด ํ”„๋กœํผํ‹ฐ์—๋Š” ๋ฐฑํ‚น ํ•„๋“œ๊ฐ€ ์—†์œผ๋ฏ€๋กœ ์ดˆ๊ธฐํ™”๊ฐ€ ํ—ˆ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค"๋‹ค. get()๊ณผ set() ์–ด๋А ์ชฝ์—๋„ field ํ‚ค์›Œ๋“œ๊ฐ€ ์“ฐ์ด์ง€ ์•Š์„ ๋•Œ, ์ดˆ๊ธฐํ™” ์ฝ”๋“œ๋ฅผ ์จ๋„ฃ์œผ๋ฉด ์ด ์—๋Ÿฌ๊ฐ€ ๋‚œ๋‹ค. ์œ„ ์ฝ”๋“œ๋Œ€๋กœ๋ผ๋ฉด name์— ๋ฌด์Šจ ๊ฐ’์„ ํ• ๋‹น(Setter)ํ•˜๋“ , ์–ธ์ œ ์ฐธ์กฐ(Getter)ํ•˜๋“  "steve"๋ผ๋Š” ์ดˆ๊ธฐํ™” ๊ฐ’์—๋Š” ์ ˆ๋Œ€ ๋„๋‹ฌํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์—, ์ดˆ๊ธฐํ™”๋ฅผ ํ•˜๋Š” ์˜๋ฏธ๊ฐ€ ์—†๋‹ค. ๊ทธ๋ž˜์„œ ๋ฉ”๋ชจ๋ฆฌ ์ ˆ์•ฝ์„ ์œ„ํ•ด ๋ฐฑํ‚น ํ•„๋“œ๋„ ์ƒ์„ฑ๋˜์ง€ ์•Š๋Š” ๊ฒƒ์ด๋‹ค. #1-2์—์„œ ๋ฐฑํ‚น ํ•„๋“œ๋Š” ์ž์ฒด์ ์œผ๋กœ ์กด์žฌํ•  ์ˆ˜ ์—†๊ณ , ์˜ค์ง ํ”„๋กœํผํ‹ฐ์˜ ๊ฐ’์„ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•ด ์กด์žฌํ•˜๋Š”, ํ”„๋กœํผํ‹ฐ์— ์ข…์†๋œ ์ €์žฅ์†Œ๋ผ๊ณ  ํ–ˆ๋‹ค. ์ €์žฅ์†Œ๊ฐ€ ์—†์œผ๋‹ˆ ํ”„๋กœํผํ‹ฐ์— ๊ฐ’์„ ๋„ฃ์„ ์ˆ˜ ์—†๋‹ค. ๊ทธ๋ž˜์„œ ์—๋Ÿฌ๊ฐ€ ๋‚œ๋‹ค.