[Kotlin] copy()와 λΆˆλ³€μ„±

πŸ’‘ Kotlinμ—μ„œ 객체의 μƒνƒœλ₯Ό λ³€κ²½ν•  수 μžˆλŠ”μ§€ μ—¬λΆ€λ₯Ό λ‚˜νƒ€λ‚΄λŠ” λΆˆλ³€μ„±κ³Ό 가변성에 λŒ€ν•˜μ—¬ ν•™μŠ΅ν•˜μ˜€μŠ΅λ‹ˆλ‹€.

λΆˆλ³€μ„± (Immutability)

  • λΆˆλ³€ κ°μ²΄λŠ” μƒμ„±λœ 이후에 μƒνƒœλ₯Ό λ³€κ²½ν•  수 μ—†λŠ” κ°μ²΄μž…λ‹ˆλ‹€.
  • μ΄λŸ¬ν•œ κ°μ²΄λŠ” 생성할 λ•Œ 값을 μ„€μ •ν•˜κ³ , μ΄ν›„μ—λŠ” 값을 λ³€κ²½ν•  수 μ—†μŠ΅λ‹ˆλ‹€.
  • Kotlinμ—μ„œλŠ” val ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ λΆˆλ³€ λ³€μˆ˜λ₯Ό μ„ μ–Έν•©λ‹ˆλ‹€.
  • Kotlin은 ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ°μ„ μ§€μ›ν•˜λŠ” μ–Έμ–΄λ‘œ, λΆˆλ³€μ„±μ˜ μ‚¬μš©μ„ ꢌμž₯ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

λΆˆλ³€μ„±μ˜ μ€‘μš”μ„±

  • λΆˆλ³€ κ°μ²΄λŠ” 생성 μ‹œμ  이후 ν•œ 번 μ •μ˜λœ μƒνƒœλŠ” 계속 μœ μ§€ν•˜λ©° λ³€κ²½λ˜μ§€ μ•ŠμœΌλ―€λ‘œ μŠ€λ ˆλ“œ κ°„ μ•ˆμ „μ„±μ„ 보μž₯ν•˜λ©°, 이λ₯Ό 톡해 동기화 문제λ₯Ό ν•΄κ²°ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • λ˜ν•œ ν•œ 번 μƒμ„±ν•œ 값은 λ³€κ²½λ˜μ§€ μ•ŠμœΌλ―€λ‘œ μΊμ‹œλ„ μˆ˜μ›”ν•©λ‹ˆλ‹€.
  • κΈ°μ‘΄ κ°μ²΄μ—μ„œ ν”„λ‘œνΌν‹°κ°€ λ³€κ²½λœ 객체λ₯Ό 리턴 λ°›κ³ μž ν•  λ•Œ 방어적 볡사λ₯Ό ν•˜μ§€ μ•Šμ•„λ„ λœλ‹€λŠ” μž₯점이 μžˆμŠ΅λ‹ˆλ‹€.
    • 방어적 볡사 : κ°μ²΄μ˜ λΆˆλ³€μ„±μ„ 보μž₯ν•˜κ³ , μ™ΈλΆ€μ—μ„œ 객체의 μƒνƒœλ₯Ό λ³€κ²½ν•˜μ§€ λͺ»ν•˜λ„둝 볡사본을 μ œκ³΅ν•˜λŠ” 기법
data class Person(val name: String, val birthDate: Date)

class PersonManager {
    private val birthDate = Date()

    fun getBirthDate(): Date {
        return Date(birthDate.time) // 방어적 볡사본을 λ°˜ν™˜
    }
}

fun main() {
    val manager = PersonManager()
    val birthDate = manager.getBirthDate()
    birthDate.time = 0 // μ™ΈλΆ€ μ½”λ“œμ—μ„œ birthDateλ₯Ό 변경해도 PersonManager λ‚΄λΆ€μ˜ birthDateλŠ” λ³€κ²½λ˜μ§€ μ•ŠμŒ
}
  • 방어적 λ³΅μ‚¬μ˜ μž₯점
    • 객체의 λΆˆλ³€μ„±μ„ μœ μ§€ν•  수 있으며, μ•ˆμ „μ„±κ³Ό μ½”λ“œ 예츑 κ°€λŠ₯성을 ν–₯상 μ‹œν‚΅λ‹ˆλ‹€.
    • 무결성을 μœ μ§€ν•˜κ³  μ™ΈλΆ€ μ½”λ“œλ‘œλΆ€ν„° 객체의 μƒνƒœ 변경을 λ°©μ§€ν•˜κΈ° μœ„ν•œ μ€‘μš”ν•œ κΈ°λ²•μž…λ‹ˆλ‹€.
  • 방어적 λ³΅μ‚¬μ˜ 단점
    • μ„±λŠ₯을 μ €ν•˜μ‹œν‚€κ³ , μ½”λ“œλ₯Ό λ³΅μž‘ν•˜κ²Œ λ§Œλ“ λ‹€λŠ” 단점을 가지고 μžˆμŠ΅λ‹ˆλ‹€.

κ°€λ³€μ„± (Mutability)

  • λΆˆλ³€μ„±κ³Ό λ°˜λŒ€λ‘œ λ³€κ²½ κ°€λŠ₯ν•œ μƒνƒœλ₯Ό κ°€μ§€λŠ” 경우λ₯Ό 가변성이라고 ν•©λ‹ˆλ‹€.
  • λ¬΄λΆ„λ³„ν•œ μƒνƒœκ°€ λ³€κ²½λ˜λŠ” κ²½μš°κ°€ λ°œμƒν•˜λ©°, μ•„λž˜μ™€ 같은 문제점이 μƒκΉλ‹ˆλ‹€.
    • λ©€ν‹°μŠ€λ ˆλ“œμ—μ„œ 값을 보μž₯ν•˜μ§€ λͺ»ν•¨
    • 예츑이 μ–΄λ ΅κ³  변경에 μœ„ν—˜ν•¨
    • ν…ŒμŠ€νŠΈμ™€ 디버깅이 어렀움

Kotlinμ—μ„œ 가변성을 μ œν•œν•˜λŠ” 방법

  • μ½”ν‹€λ¦°μ—μ„œλŠ” 3가지 κ°€λ³€μ„± μ œν•œ 방법을 μ œμ‹œν•©λ‹ˆλ‹€.
    • 읽기 μ „μš© ν”„λ‘œνΌν‹°μΈ val ν‚€μ›Œλ“œ μ‚¬μš©
    • Mutable μ»¬λ ‰μ…˜κ³Ό read-only μ»¬λ ‰μ…˜μ„ ꡬ뢄
      • Mutable μ»¬λ ‰μ…˜: MutableList, MutableSet, MutableMap..
      • read-only μ»¬λ ‰μ…˜: List, Set, Map..
    • data class의 copy() 지원

copy() ν™œμš©

data class User(
	val name: String,
	val tag: Int,

}

fun main() {
	val user = User("jinwoo",1001)
	val user_copy = user.copy(name = "jinwoo_copy")
}
  • data classμ—μ„œ copyλ₯Ό ν™œμš©ν•˜λ©΄, κΈ°μ‘΄ 객체의 값을 λ³€κ²½ν•˜μ§€ μ•Šκ³  ν”„λ‘œνΌν‹°λ₯Ό λ³€κ²½ν•˜μ—¬ μƒˆλ‘œμš΄ 값을 ν• λ‹Ήν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • λ‚΄μž₯ ν•¨μˆ˜μΈ hashCode()λ₯Ό ν™œμš©ν•˜λ©΄, 두 객체가 λ‹€λ₯Έ 값을 μ°Έμ‘°ν•˜κ³  μžˆλŠ” 것을 μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€.
  • 이λ₯Ό ν†΅ν•΄μ„œ λΆˆλ³€μ„±μ„ μœ μ§€ν•  수 μžˆμŠ΅λ‹ˆλ‹€.