개발/Kotlin

[Kotlin In Action] 4. 클래슀, 객체, μΈν„°νŽ˜μ΄μŠ€

도리 🐟 2021. 5. 19. 17:13

#1. 클래슀 계측 μ •μ˜

μΈν„°νŽ˜μ΄μŠ€

μ½”ν‹€λ¦° μΈν„°νŽ˜μ΄μŠ€ μ•ˆμ—λŠ” 좔상 λ©”μ„œλ“œλΏ μ•„λ‹ˆλΌ κ΅¬ν˜„μ΄ μžˆλŠ” λ©”μ„œλ“œλ„ μ •μ˜ν•  수 μžˆλ‹€.
μƒνƒœ(ν•„λ“œ)λŠ” λ“€μ–΄κ°ˆ 수 μ—†λ‹€.

//μΈν„°νŽ˜μ΄μŠ€ μ •μ˜
interface Clickable { 
    fun click()
}

//μΈν„°νŽ˜μ΄μŠ€ κ΅¬ν˜„
class Button : Clickable { //코틀린은 클래슀 ν™•μž₯κ³Ό μΈν„°νŽ˜μ΄μŠ€ κ΅¬ν˜„ λͺ¨λ‘ 콜둠(:)을 뢙인닀.
    //μ˜€λ²„λΌμ΄λ“œ ν‘œμ‹œ
    override fun click() = println("I was clicked")
}

μžλ°”μ™€ λ§ˆμ°¬κ°€μ§€λ‘œ μΈν„°νŽ˜μ΄μŠ€λŠ” 개수 μ œν•œμ—†μ΄ λ§ˆμŒλŒ€λ‘œ κ΅¬ν˜„ν•  수 μžˆμ§€λ§Œ, ν΄λž˜μŠ€λŠ” 였직 ν•˜λ‚˜λ§Œ ν™•μž₯ν•  수 μžˆλ‹€.

 

μƒμœ„ ν΄λž˜μŠ€μ— μžˆλŠ” λ©”μ„œλ“œμ™€ μ‹œκ·Έλ‹ˆμ²˜κ°€ 같은 λ©”μ„œλ“œλ₯Ό μš°μ—°νžˆ ν•˜μœ„ ν΄λž˜μŠ€μ— μ„ μ–Έν•˜λŠ” 경우, 컴파일이 μ•ˆ 되기 λ•Œλ¬Έμ— overrideλ₯Ό λΆ™μ΄κ±°λ‚˜ λ©”μ„œλ“œ 이름을 λ°”κΏ”μ•Ό ν•œλ‹€.

 

  • μ˜ˆμ‹œ) λ™μΌν•œ λ©”μ„œλ“œκ°€ μžˆλŠ” μΈν„°νŽ˜μ΄μŠ€λ₯Ό λ™μ‹œμ— κ΅¬ν˜„ν•  λ•Œ
interface Clickable {
    fun click()
    fun showOff() = println("I'm clickable!") //λ””ν΄νŠΈ κ΅¬ν˜„ μ •μ˜
}

interface Focusable {
    fun setFocus(b: Boolean) =
        println("I ${if (b) "got" else "lost"} focus.")
    fun showOff() = println("I'm focusable!")
}

 

ν΄λž˜μŠ€κ°€ κ΅¬ν˜„ν•˜λŠ” 두 μƒμœ„ μΈν„°νŽ˜μ΄μŠ€μ— μ •μ˜λœ showOff κ΅¬ν˜„을 λŒ€μ²΄ν•  μ˜€λ²„λΌμ΄λ”© λ©”μ„œλ“œλ₯Ό 직접 μ œκ³΅ν•˜μ§€ μ•ŠμœΌλ©΄ 컴파일 였λ₯˜κ°€ λ°œμƒν•œλ‹€.

The class 'Button' must override public open fun showOff() because it inherits many implementations of it.

 

이름과 μ‹œκ·Έλ‹ˆμ²˜κ°€ 같은 멀버 λ©”μ„œλ“œμ— λŒ€ν•΄ λ‘˜ μ΄μƒμ˜ λ””ν΄νŠΈ κ΅¬ν˜„μ΄ μžˆλŠ” 경우, μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜λŠ” ν•˜μœ„ ν΄λž˜μŠ€μ—μ„œ λͺ…μ‹œμ μœΌλ‘œ μƒˆλ‘œμš΄ κ΅¬ν˜„μ„ μ œκ³΅ν•΄μ•Ό ν•œλ‹€.

class Button : Clickable, Focusable {
    override fun click() = println("I was clicked")
    
    override fun showOff() {
        super<Clickable>.showOff()
        super<Focusable>.showOff()
    }
}

super 처럼 κΊ½μ‡  μ•ˆμ— νƒ€μž…μ„ μ§€μ •ν•œλ‹€. (μžλ°”μ—μ„œλŠ” Clickable.super)

코틀린은 μžλ°” 6κ³Ό ν˜Έν™˜λ˜λ―€λ‘œ, μžλ°”μ—μ„œλŠ” μ½”ν‹€λ¦°μ˜ λ””ν΄νŠΈ λ©”μ„œλ“œ κ΅¬ν˜„μ— μ˜μ‘΄ν•  수 μ—†λ‹€. λ””ν΄νŠΈ λ©”μ„œλ“œκ°€ μžˆλŠ” μΈν„°νŽ˜μ΄μŠ€λ₯Ό 일반 μΈν„°νŽ˜μ΄μŠ€μ™€ λ””ν΄νŠΈ λ©”μ„œλ“œ κ΅¬ν˜„μ΄ 정적 λ©”μ„œλ“œλ‘œ λ“€μ–΄μžˆλŠ” 클래슀λ₯Ό μ‘°ν•©ν•΄ κ΅¬ν˜„λœλ‹€.

open, final, abstract

μ½”ν‹€λ¦°μ˜ ν΄λž˜μŠ€μ™€ λ©”μ„œλ“œλŠ” 기본적으둜 final이닀.
상속을 ν—ˆμš©ν•˜λ €λ©΄ open λ³€κ²½μžλ₯Ό λΆ™μ—¬μ•Ό ν•œλ‹€.
μ˜€λ²„λΌμ΄λ“œλ₯Ό ν—ˆμš©ν•˜κ³  싢은 λ©”μ„œλ“œλ‚˜ ν”„λ‘œνΌν‹° μ•žμ—λ„ open λ³€κ²½μžλ₯Ό λΆ™μ—¬μ•Ό ν•œλ‹€.

open class RichButton : Clickable { //이 ν΄λž˜μŠ€λŠ” μ—΄λ € μžˆλ‹€.
    fun disable() {} //이 ν•¨μˆ˜λŠ” μ˜€λ²„λΌμ΄λ“œν•  수 μ—†λ‹€.
    open fun animate() {} //μ˜€λ²„λΌμ΄λ“œ κ°€λŠ₯ν•˜λ‹€.
    override fun click() {} //μƒμœ„ 클래슀의 λ©”μ„œλ“œλ₯Ό μ˜€λ²„λΌμ΄λ“œν•œλ‹€. (μ˜€λ²„λΌμ΄λ“œν•œ λ©”μ„œλ“œλŠ” 기본으둜 μ—΄λ €μžˆλ‹€.)
}

open class RichButton : Clickable {
    final override fun click() {} //μ˜€λ²„λΌμ΄λ“œν•œ λ©”μ„œλ“œμ˜ κ΅¬ν˜„μ„ ν•˜μœ„ ν΄λž˜μŠ€μ—μ„œ μ˜€λ²„λΌμ΄λ“œν•˜μ§€ λͺ»ν•˜κ²Œ ν•˜λ €λ©΄ final을 뢙인닀.
}

abstract: 좔상 클래슀 μ„ μ–Έ
좔상 λ©€λ²„λŠ” 항상 μ—΄λ € μžˆλ‹€. -> open을 뢙일 ν•„μš”κ°€ μ—†λ‹€.

 

μΈν„°νŽ˜μ΄μŠ€ λ©€λ²„λŠ” final, open, abstractλ₯Ό μ‚¬μš©ν•˜μ§€ μ•ŠλŠ”λ‹€.
μΈν„°νŽ˜μ΄μŠ€ λ©€λ²„λŠ” 항상 μ—΄λ € 있으며 final둜 λ³€κ²½ν•  수 μ—†λ‹€.

λ³€κ²½μž μ˜€λ²„λΌμ΄λ“œ μ„€λͺ…
fianl λΆˆκ°€λŠ₯ 클래슀 λ©€λ²„μ˜ κΈ°λ³Έ λ³€κ²½μž
open κ°€λŠ₯ open을 λͺ…μ‹œν•΄μ•Ό μ˜€λ²„λΌμ΄λ“œ κ°€λŠ₯
abstract ν•„μˆ˜ 좔상 클래슀의 λ©€λ²„μ—λ§Œ 뢙일 수 μžˆλ‹€.
좔상 λ©€λ²„λŠ” κ΅¬ν˜„μ΄ 있으면 μ•ˆ λœλ‹€.

 

κ°€μ‹œμ„± λ³€κ²½μž

: 선언에 λŒ€ν•œ 클래슀 μ™ΈλΆ€μ˜ 접근을 μ œμ–΄ν•œλ‹€.

 

아무 λ³€κ²½μžλ„ μ—†λŠ” 경우 λͺ¨λ‘ public 이닀.

코틀린은 package-private을 μ‚¬μš©ν•˜μ§€ μ•ŠλŠ”λ‹€. (νŒ¨ν‚€μ§€λ₯Ό λ„€μž„μŠ€νŽ˜μ΄μŠ€ 관리 μš©λ„λ‘œλ§Œ μ‚¬μš©ν•˜κΈ° λ•Œλ¬Έ)
λŒ€μ‹  internal을 λ„μž…: λͺ¨λ“ˆ λ‚΄λΆ€μ—μ„œλ§Œ λ³Ό 수 있음

 

코틀린은 μ΅œμƒμœ„ μ„ μ–Έ(클래슀, ν•¨μˆ˜, ν”„λ‘œνΌν‹°)에 λŒ€ν•΄ private κ°€μ‹œμ„±μ„ μ œκ³΅ν•œλ‹€.
-> κ·Έ 선언이 λ“€μ–΄μžˆλŠ” νŒŒμΌ λ‚΄λΆ€μ—μ„œλ§Œ μ‚¬μš©ν•  수 μžˆλ‹€.

 

λ³€κ²½μž 클래슀 멀버 μ΅œμƒμœ„ μ„ μ–Έ
public (default) λͺ¨λ“  κ³³μ—μ„œ λͺ¨λ“  κ³³μ—μ„œ
internal 같은 λͺ¨λ“ˆ μ•ˆμ—μ„œλ§Œ 같은 λͺ¨λ“ˆ μ•ˆμ—μ„œλ§Œ
protected ν•˜μœ„ 클래슀 μ•ˆμ—μ„œλ§Œ (μ΅œμƒμœ„ 선언에 적용 λΆˆκ°€λŠ₯)
private 같은 클래슀 μ•ˆμ—μ„œλ§Œ 같은 파일 μ•ˆμ—μ„œλ§Œ
  1. μ–΄λ–€ 클래슀의 기반 νƒ€μž… λͺ©λ‘μ— λ“€μ–΄μžˆλŠ” νƒ€μž…μ΄λ‚˜ μ œλ„€λ¦­ 클래슀의 νƒ€μž… νŒŒλΌλ―Έν„°μ— λ“€μ–΄μžˆλŠ” νƒ€μž…μ˜ κ°€μ‹œμ„±μ€ 클래슀 μžμ‹ μ˜ κ°€μ‹œμ„±κ³Ό κ°™κ±°λ‚˜ λ†’μ•„μ•Ό ν•˜κ³ ,
  2. λ©”μ„œλ“œ μ‹œκ·Έλ‹ˆμ²˜μ— μ‚¬μš©λœ λͺ¨λ“  νƒ€μž…μ˜ κ°€μ‹œμ„±μ€ κ·Έ λ©”μ„œλ“œμ˜ κ°€μ‹œμ„±κ³Ό κ°™κ±°λ‚˜ λ†’μ•„μ•Ό ν•œλ‹€.

μ½”ν‹€λ¦°μ—μ„œλŠ” μ™ΈλΆ€ ν΄λž˜μŠ€κ°€ λ‚΄λΆ€ ν΄λž˜μŠ€λ‚˜ μ€‘μ²©λœ ν΄λž˜μŠ€μ˜ private λ©€λ²„에 μ ‘κ·Όν•  μˆ˜ μ—†λ‹€.

λ‚΄λΆ€ ν΄λž˜μŠ€μ™€ μ€‘μ²©λœ 클래슀

μ½”ν‹€λ¦°μ˜ 쀑첩 ν΄λž˜μŠ€λŠ” λͺ…μ‹œμ μœΌλ‘œ μš”μ²­ν•˜μ§€ μ•ŠλŠ” ν•œ λ°”κΉ₯ 클래슀 μΈμŠ€ν„΄μŠ€μ— λŒ€ν•œ μ ‘κ·Ό κΆŒν•œμ΄ μ—†λ‹€.

λ°”κΉ₯ ν΄λž˜μŠ€μ— λŒ€ν•œ μ°Έμ‘°λ₯Ό ν¬ν•¨ν•˜κ³  μ‹Άλ‹€λ©΄ inner λ³€κ²½μžλ₯Ό λΆ™μ—¬μ•Ό ν•œλ‹€.

클래슀 계측을 λ§Œλ“€λ˜ κ·Έ 계측에 μ†ν•œ 클래슀의 수λ₯Ό μ œν•œν•˜κ³  싢은 경우 쀑첩 클래슀λ₯Ό μ“°λ©΄ νŽΈλ¦¬ν•˜λ‹€.

sealed 클래슀

μƒμœ„ 클래슀λ₯Ό μƒμ†ν•œ ν•˜μœ„ 클래슀 μ •μ˜λ₯Ό μ œν•œν•  수 μžˆλ‹€.
sealed 클래슀의 ν•˜μœ„ 클래슀λ₯Ό μ •μ˜ν•  λ•ŒλŠ” λ°˜λ“œμ‹œ μƒμœ„ 클래슀 μ•ˆμ— μ€‘μ²©μ‹œμΌœμ•Ό ν•œλ‹€. (1.0 버전)

 

1.1 λ²„μ „λΆ€ν„°λŠ” 같은 파일 μ•ˆμ— ν•˜μœ„ 클래슀λ₯Ό λ§Œλ“€ 수 μžˆλ‹€.
1.5 λ²„μ „λΆ€ν„°λŠ” sealed μΈν„°νŽ˜μ΄μŠ€λ„ μ •μ˜ κ°€λŠ₯ν•˜λ‹€.

 

sealed class Expr {
    class Num(val value: Int) : Expr()
    class Sum(val left: Expr, val right: Expr) : Expr()
}

when μ‹μ—μ„œ sealed 클래슀의 λͺ¨λ“  ν•˜μœ„ 클래슀λ₯Ό μ²˜λ¦¬ν•œλ‹€λ©΄ else λΆ„κΈ°λŠ” ν•„μš” μ—†λ‹€.

#2. λ»”ν•˜μ§€ μ•Šμ€ μƒμ„±μžμ™€ ν”„λ‘œνΌν‹°λ₯Ό κ°–λŠ” 클래슀 μ„ μ–Έ

코틀린은 μ£Ό μƒμ„±μž(primary constructor), λΆ€ μƒμ„±μž(secondary constructor), μ΄ˆκΈ°ν™” λΈ”λŸ­μ„ μ œκ³΅ν•œλ‹€.

constructor ν‚€μ›Œλ“œλ‘œ μ£Ό μƒμ„±μžλ‚˜ λΆ€ μƒμ„±μžλ₯Ό μ •μ˜ν•œλ‹€.

클래슀 μ΄ˆκΈ°ν™”: μ£Ό μƒμ„±μžμ™€ μ΄ˆκΈ°ν™” λΈ”λŸ­

μ£Ό μƒμ„±μž

  1. μƒμ„±μž νŒŒλΌλ―Έν„° 지정
  2. μ΄ˆκΈ°ν™”λ˜λŠ” ν”„λ‘œνΌν‹°λ₯Ό μ •μ˜
class User constructor(_nickname: String) { //μ£Ό μƒμ„±μž μ •μ˜
    val nickname: String
    
    init { //μ΄ˆκΈ°ν™” λΈ”λŸ­
        nickname = _nickname
    }
}

μ΄ˆκΈ°ν™” λΈ”λŸ­μ€ μΈμŠ€ν„΄μŠ€ν™”λ  λ•Œ 싀행될 μ΄ˆκΈ°ν™” μ½”λ“œκ°€ λ“€μ–΄κ°€λ©°, μ£Ό μƒμ„±μžμ™€ ν•¨κ»˜ μ‚¬μš©λœλ‹€.
(μ£Ό μƒμ„±μžλŠ” λ³„λ„μ˜ μ½”λ“œλ₯Ό 포함할 수 μ—†μœΌλ―€λ‘œ μ΄ˆκΈ°ν™” λΈ”λŸ­μ΄ ν•„μš”ν•˜λ‹€.)
μ΄ˆκΈ°ν™” λΈ”λŸ­μ€ μ—¬λŸ¬ 개 생성 κ°€λŠ₯ν•˜λ‹€.

 

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

 

μ£Ό μƒμ„±μžμ˜ νŒŒλΌλ―Έν„°λ‘œ ν”„λ‘œνΌν‹°λ₯Ό μ΄ˆκΈ°ν™”ν•œλ‹€λ©΄, κ·Έ νŒŒλΌλ―Έν„°μ— val을 μΆ”κ°€ν•˜λŠ” λ°©μ‹μœΌλ‘œ ν”„λ‘œνΌν‹° μ •μ˜μ™€ μ΄ˆκΈ°ν™”λ₯Ό κ°„λž΅νžˆ μ“Έ 수 μžˆλ‹€.

class User(val nickname: String,
           val isSubscribed: Boolean = true) //μƒμ„±μž νŒŒλΌλ―Έν„°μ—λ„ λ””ν΄νŠΈ 값을 μ •μ˜ν•  수 μžˆλ‹€.

객체 생성 μ‹œμ—λŠ” new ν‚€μ›Œλ“œμ—†μ΄ 직접 ν˜ΈμΆœν•œλ‹€.

val alice = User("Alice")

 

λͺ¨λ“  μƒμ„±μž νŒŒλΌλ―Έν„°μ— λ””ν΄νŠΈ 값을 μ§€μ •ν•˜λ©΄ μ»΄νŒŒμΌλŸ¬κ°€ μžλ™μœΌλ‘œ νŒŒλΌλ―Έν„°κ°€ μ—†λŠ” μƒμ„±μžλ₯Ό λ§Œλ“€μ–΄μ€€λ‹€.
λ³„λ„λ‘œ μƒμ„±μžλ₯Ό μ •μ˜ν•˜μ§€ μ•Šμ•˜μ„ λ•Œλ„ μžλ™μœΌλ‘œ νŒŒλΌλ―Έν„°κ°€ μ—†λŠ” λ””ν΄νŠΈ μƒμ„±μžλ₯Ό λ§Œλ“€μ–΄μ€€λ‹€.

 

기반 ν΄λž˜μŠ€κ°€ μžˆλŠ” 경우, λ°˜λ“œμ‹œ 기반 클래슀의 μƒμ„±μžλ₯Ό ν˜ΈμΆœν•΄μ•Ό ν•œλ‹€.

open class User(val nickname: String) { ... }

class TwitterUser(nickname: String) : User(nickname) { ... } //기반 ν΄λž˜μŠ€μ— μƒμ„±μž νŒŒλΌλ―Έν„°λ₯Ό λ„˜κΉ€

class RadioButton: Button() //Button의 μƒμ„±μž 호좜

클래슀 μ™ΈλΆ€μ—μ„œ μΈμŠ€ν„΄μŠ€ν™”ν•˜μ§€ λͺ»ν•˜κ²Œ 막고 μ‹Άλ‹€λ©΄ λͺ¨λ“  μƒμ„±μžλ₯Ό private으둜 λ§Œλ“ λ‹€.

class Secretive private constructor() {} //μ£Ό μƒμ„±μžλ₯Ό private으둜 λ§Œλ“œλŠ” μ˜ˆμ‹œ

λΆ€ μƒμ„±μž

ν΄λž˜μŠ€μ— μ£Ό μƒμ„±μžκ°€ μ—†λ‹€λ©΄ λͺ¨λ“  λΆ€ μƒμ„±μžλŠ” λ°˜λ“œμ‹œ μƒμœ„ 클래슀λ₯Ό μ΄ˆκΈ°ν™”ν•˜κ±°λ‚˜ λ‹€λ₯Έ μƒμ„±μžμ—κ²Œ 생성을 μœ„μž„ν•΄μ•Ό ν•œλ‹€.
λΆ€ μƒμ„±μžμ˜ μ£Ό λͺ©μ μ€ μžλ°” μƒν˜Έμš΄μš©μ„±μ΄μ§€λ§Œ, 클래슀 μΈμŠ€ν„΄μŠ€λ₯Ό 생성할 λ•Œ νŒŒλΌλ―Έν„° λͺ©λ‘μ΄ λ‹€λ₯Έ 생성 방법이 μ—¬λŸΏ μ‘΄μž¬ν•˜λŠ” κ²½μš°μ—λŠ” λΆ€ μƒμ„±μžλ₯Ό μ—¬λŸΏ λ‘˜ 수 밖에 μ—†λ‹€.

class MyButton : View {
    constructor(ctx: Context): this(ctx, MY_STYLE) { //this: μžμ‹ μ˜ λ‹€λ₯Έ μƒμ„±μžμ— μœ„μž„ν•œλ‹€.
        // ... 
    }

    constructor(ctx: Context, attr: AttributeSet): super(ctx, attr) { //super: μƒμœ„ 클래슀의 μƒμ„±μžλ₯Ό ν˜ΈμΆœν•œλ‹€.
        // ...
    } 
}

μΈν„°νŽ˜μ΄μŠ€μ— μ„ μ–Έλœ ν”„λ‘œνΌν‹° κ΅¬ν˜„

μ½”ν‹€λ¦°μ—μ„œλŠ” μΈν„°νŽ˜μ΄μŠ€μ— μΆ”상 ν”„λ‘œνΌν‹° 선언을 넣을 수 μžˆλ‹€.

interface User {
    val nickname: String
}

-> nickname의 값을 얻을 수 μžˆλŠ” 방법을 μ œκ³΅ν•΄μ•Ό ν•œλ‹€λŠ” λœ»μ΄λ‹€.

 

κ΅¬ν˜„ 방법 1) μ£Ό μƒμ„±μž μ•ˆμ— 직접 μ„ μ–Έν•˜κΈ°

class PrivateUser(override val nickname: String) : User

User의 ν”„λ‘œνΌν‹°λ₯Ό κ΅¬ν˜„ν•˜λŠ” κ²ƒμ΄λ―€λ‘œ, overrideλ₯Ό λΆ™μ—¬μ€˜μ•Ό ν•œλ‹€.

 

κ΅¬ν˜„ 방법 2) Custom Getter

class SubscribingUser(val email: String) : User {
    override val nickname: String
        get() = email.substringBefore('@') )
}

-> λ’·λ°›μΉ¨ν•˜λŠ” ν•„λ“œ(backing field)에 μ €μž₯ν•˜μ§€ μ•Šκ³ , 맀번 이메일 μ£Όμ†Œμ—μ„œ nickname을 계산해 λ°˜ν™˜ν•œλ‹€.

 

κ΅¬ν˜„ 방법 3) ν”„λ‘œνΌν‹° μ΄ˆκΈ°ν™” 식

class FacebookUser(val accountId: Int) : User {
    override val nickname = getFacebookName(accountId)
}

-> μ΄ˆκΈ°ν™” λ‹¨κ³„μ—μ„œ getFacebookName이 ν•œ 번만 ν˜ΈμΆœλœλ‹€.
객체 μ΄ˆκΈ°ν™” μ‹œ κ³„μ‚°ν•œ 데이터λ₯Ό λ’·λ°›μΉ¨ν•˜λŠ” ν•„λ“œμ— μ €μž₯ν–ˆλ‹€κ°€ λΆˆλŸ¬μ˜€λŠ” 방식을 ν™œμš©ν•œλ‹€.


μΈν„°νŽ˜μ΄μŠ€μ—λŠ” 좔상 ν”„λ‘œνΌν‹° 뿐만 μ•„λ‹ˆλΌ Getter와 Setterκ°€ μžˆλŠ” ν”„λ‘œνΌν‹°λ₯Ό μ„ μ–Έν•  수 μžˆλ‹€.
Getter, SetterλŠ” λ’·λ°›μΉ¨ν•˜λŠ” ν•„λ“œλ₯Ό μ°Έμ‘°ν•  수 μ—†λ‹€.

interface User {
    val email: String //λ°˜λ“œμ‹œ μ˜€λ²„λΌμ΄λ“œν•΄μ•Ό ν•œλ‹€.
    val nickname: String
        get() = email.substringBefore('@')
}

Getter와 Setterμ—μ„œ λ’·λ°›μΉ¨ν•˜λŠ” ν•„λ“œ(Backing field) μ ‘κ·Ό

class User(val name: String) {
    var address: String = "unspecified"
        set(value: String) {
            println("""
                Address was changed for $name:
                "$field" -> "$value".""".trimIndent()) //field둜 κ°’ 읽기
            field = value //backing field κ°’ λ³€κ²½
        }
}

fieldλΌλŠ” μ‹λ³„μžλ₯Ό 톡해 λ’·λ°›μΉ¨ν•˜λŠ” ν•„λ“œμ— μ ‘κ·Όν•  수 μžˆλ‹€.
Getterμ—μ„œλŠ” field 값을 읽을 수만 있고, Setterμ—μ„œλŠ” field 값을 μ½κ±°λ‚˜ μ“Έ 수 μžˆλ‹€.
fieldλ₯Ό μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” μ»€μŠ€ν…€ μ ‘κ·Όμžλ₯Ό κ΅¬ν˜„ν•˜λ©΄ λ’·λ°›μΉ¨ν•˜λŠ” ν•„λ“œλŠ” μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ”λ‹€.
(val인 경우 Getter에 fieldκ°€ μ—†μœΌλ©΄ λ˜μ§€λ§Œ, var인 경우 Getter/Setter λͺ¨λ‘ μ—†μ–΄μ•Ό ν•œλ‹€.)

μ ‘κ·Όμžμ˜ κ°€μ‹œμ„± λ³€κ²½

μ ‘κ·Όμžμ˜ κ°€μ‹œμ„±μ€ 기본적으둜 ν”„λ‘œνΌν‹°μ˜ κ°€μ‹œμ„±κ³Ό κ°™λ‹€.
변경을 μ›ν•œλ‹€λ©΄ getμ΄λ‚˜ set μ•žμ— κ°€μ‹œμ„± λ³€κ²½μžλ₯Ό μΆ”κ°€ν•œλ‹€.

class LengthCounter {
    var counter: Int = 0
        private set //Setterλ₯Ό private으둜 λ§Œλ“ λ‹€.
}

#3. 데이터 ν΄λž˜μŠ€μ™€ 클래슀 μœ„μž„

λͺ¨λ“  ν΄λž˜μŠ€κ°€ μ •μ˜ν•΄μ•Ό ν•˜λŠ” λ©”μ„œλ“œ

1. toString()

 

κΈ°λ³Έ μ œκ³΅λ˜λŠ” 객체의 λ¬Έμžμ—΄ ν‘œν˜„μ€ Client@5e9f23b4와 같은 방식인데, κΈ°λ³Έ κ΅¬ν˜„μ„ λ°”κΎΈλ €λ©΄ toString()을 μ˜€λ²„λΌμ΄λ“œ ν•΄μ•Ό ν•œλ‹€. (μžλ°”μ™€ 동일)

 

2. equals(), hashCode()

 

객체의 동등성 검사

μ½”ν‹€λ¦°μ—μ„œλŠ” == μ—°μ‚°μžλ‘œ equals 검사λ₯Ό ν•œλ‹€.
μ°Έμ‘° 동일성 κ²€μ‚¬λŠ” ===을 μ΄μš©ν•œλ‹€.

data class

데이터λ₯Ό μ €μž₯ν•˜λŠ” μ—­ν• λ§Œ ν•˜λŠ” 클래슀
data classλŠ” ν•„μš”ν•œ λ©”μ„œλ“œλ₯Ό μ»΄νŒŒμΌλŸ¬κ°€ μžλ™μœΌλ‘œ λ§Œλ“€μ–΄ μ€€λ‹€.

  • equals()
  • hashCode()
  • toString()

equals와 hashCodeλŠ” μ£Ό μƒμ„±μžμ— λ‚˜μ—΄λœ λͺ¨λ“  ν”„λ‘œνΌν‹°λ₯Ό κ³ λ €ν•΄ λ§Œλ“€μ–΄μ§„λ‹€.
-> μ£Ό μƒμ„±μž 밖에 μ •μ˜λœ ν”„λ‘œνΌν‹°λŠ” κ³ λ € λŒ€μƒμ΄ μ•„λ‹ˆλ‹€.

copy()

데이터 클래슀의 λͺ¨λ“  ν”„λ‘œνΌν‹°λ₯Ό 읽기 μ „μš©μœΌλ‘œ λ§Œλ“€μ–΄μ„œ λΆˆλ³€ 클래슀둜 λ§Œλ“œλŠ” 것을 ꢌμž₯ν•œλ‹€.
(HashMap λ“±μ˜ μ»¨ν…Œμ΄λ„ˆμ— 객체λ₯Ό λ‹΄λŠ” κ²½μš°μ—λŠ” λΆˆλ³€μ„±μ΄ ν•„μˆ˜μ μ΄λ‹€.)
닀쀑 μŠ€λ ˆλ“œ ν”„λ‘œκ·Έλž¨μΈ 경우 λΆˆλ³€μ„±μ΄ λ”μš± μ€‘μš”ν•˜λ‹€.

 

데이터 클래슀λ₯Ό λΆˆλ³€ 객체둜 더 μ‰½κ²Œ ν™œμš©ν•  수 μžˆλ„λ‘ 객체λ₯Ό λ³΅μ‚¬ν•˜λ©΄μ„œ 일뢀 ν”„λ‘œνΌν‹°λ₯Ό λ°”κΏ€ 수 μžˆλŠ” copy λ©”μ„œλ“œλ₯Ό μ œκ³΅ν•œλ‹€.

클래슀 μœ„μž„: by

by ν‚€μ›Œλ“œλ₯Ό 톡해 κ·Έ μΈν„°νŽ˜μ΄μŠ€μ— λŒ€ν•œ κ΅¬ν˜„μ„ λ‹€λ₯Έ 객체에 μœ„μž„μ€‘μ΄λΌλŠ” 것을 λͺ…μ‹œν•  수 μžˆλ‹€.

class CountingSet<T>(
        val innerSet: MutableCollection<T> = HashSet<T>()
) : MutableCollection<T> by innerSet { //MutableCollection의 κ΅¬ν˜„μ„ innerSet에 μœ„μž„ν•œλ‹€.

    var objectsAdded = 0

    override fun add(element: T): Boolean { //이 λ©”μ„œλ“œλŠ” μœ„μž„ν•˜μ§€ μ•Šκ³  μƒˆλ‘œμš΄ κ΅¬ν˜„μ„ μ œκ³΅ν•œλ‹€.
        objectsAdded++
        return innerSet.add(element)
    }
}

#4. object: 클래슀 μ„ μ–Έκ³Ό μΈμŠ€ν„΄μŠ€ 생성

클래슀λ₯Ό μ •μ˜ν•˜λ©΄μ„œ λ™μ‹œμ— μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•œλ‹€.

  • objectλŠ” μ‹±κΈ€ν„΄ μ •μ˜ 방법 쀑 ν•˜λ‚˜μ΄λ‹€.
  • companion object(λ™λ°˜κ°μ²΄)λŠ” μΈμŠ€ν„΄μŠ€ λ©”μ„œλ“œλŠ” μ•„λ‹ˆμ§€λ§Œ μ–΄λ–€ ν΄λž˜μŠ€μ™€ κ΄€λ ¨μžˆλŠ” λ©”μ„œλ“œμ™€ νŒ©ν† λ¦¬ λ©”μ„œλ“œλ₯Ό 담을 λ•Œ 쓰인닀.
  • object 식은 μžλ°”μ˜ 무λͺ… λ‚΄λΆ€ 클래슀 λŒ€μ‹  쓰인닀.

객체 μ„ μ–Έ: μ‹±κΈ€ν„΄ μ‰½κ²Œ λ§Œλ“€κΈ°

: 클래슀 μ„ μ–Έκ³Ό ν΄λž˜μŠ€μ— μ†ν•œ 단일 μΈμŠ€ν„΄μŠ€μ˜ 선언을 ν•©μΉœ 말이닀.

 

객체 선언에 μƒμ„±μžλŠ” μ“Έ 수 μ—†λ‹€.
μ‹±κΈ€ν„΄ 객체가 객체 선언문이 μžˆλŠ” μœ„μΉ˜μ—μ„œ μ¦‰μ‹œ λ§Œλ“€μ–΄μ§„λ‹€.

 

κ΅¬ν˜„ 내뢀에 λ‹€λ₯Έ μƒνƒœκ°€ ν•„μš”ν•˜μ§€ μ•Šμ€ κ²½μš°μ— μœ μš©ν•˜λ‹€.

- μ½”ν‹€λ¦° 객체λ₯Ό μžλ°”μ—μ„œ μ‚¬μš©ν•  λ•Œ
μ½”ν‹€λ¦° 객체 선언은 μœ μΌν•œ μΈμŠ€ν„΄μŠ€μ— λŒ€ν•œ 정적 ν•„λ“œκ°€ μžˆλŠ” μžλ°” 클래슀둜 μ»΄νŒŒμΌλœλ‹€.
μΈμŠ€ν„΄μŠ€ ν•„λ“œ 이름은 항상 INSTANCE 이닀.

 

λ™λ°˜ 객체: νŒ©ν† λ¦¬ λ©”μ„œλ“œμ™€ 정적 멀버가 λ“€μ–΄κ°ˆ μž₯μ†Œ

코틀린은 static ν‚€μ›Œλ“œλ₯Ό μ§€μ›ν•˜μ§€ μ•ŠλŠ”λ‹€.
λŒ€μ‹  μ΅œμƒμœ„ ν•¨μˆ˜μ™€ 객체 선언을 μ œκ³΅ν•œλ‹€. (λŒ€λΆ€λΆ„μ˜ 경우 μ΅œμƒμœ„ ν•¨μˆ˜λ₯Ό 더 ꢌμž₯ν•œλ‹€.)

 

*μ΅œμƒμœ„ ν•¨μˆ˜λŠ” 클래슀의 private 멀버에 μ ‘κ·Όν•  수 μ—†λ‹€.
-> 클래슀 λ‚΄λΆ€ 정보에 μ ‘κ·Όν•΄μ•Ό ν•˜λŠ” ν•¨μˆ˜κ°€ ν•„μš”ν•  λ•ŒλŠ” ν΄λž˜μŠ€μ— μ€‘μ²©λœ 객체 μ„ μ–Έμ˜ 멀버 ν•¨μˆ˜λ‘œ μ •μ˜ν•΄μ•Ό ν•œλ‹€.

 

λ™λ°˜ κ°μ²΄λŠ” companion object ν‚€μ›Œλ“œλ‘œ λ§Œλ“€ 수 μžˆλ‹€.
λ™λ°˜ κ°μ²΄λŠ” μžμ‹ μ„ λ‘˜λŸ¬μ‹Ό 클래슀의 λͺ¨λ“  private 멀버, private μƒμ„±μžμ— μ ‘κ·Όν•  수 μžˆλ‹€.
-> νŒ©ν† λ¦¬ νŒ¨ν„΄μ„ κ΅¬ν˜„ν•˜κΈ° μ ν•©ν•˜λ‹€.

class User private constructor(val nickname: String) { //μ£Ό μƒμ„±μžλ₯Ό λΉ„κ³΅κ°œλ‘œ λ§Œλ“ λ‹€.
    companion object {
        fun newSubscribingUser(email: String) = //λ™λ°˜ 객체 μ•ˆμ— νŒ©ν† λ¦¬ λ©”μ„œλ“œλ₯Ό μ •μ˜ν•œλ‹€.
            User(email.substringBefore('@'))

        fun newFacebookUser(accountId: Int) =
            User(getFacebookName(accountId))
    }
}

λ™λ°˜ 객체λ₯Ό 일반 객체처럼 μ‚¬μš©

λ™λ°˜ κ°μ²΄λŠ” 클래슀 μ•ˆμ— μ •μ˜λœ 일반 객체이닀.
-> 객체에 이름을 λΆ™μ΄κ±°λ‚˜, λ™λ°˜ 객체가 μΈν„°νŽ˜μ΄μŠ€λ₯Ό μƒμ†ν•˜κ±°λ‚˜, λ™λ°˜ 객체 μ•ˆμ— ν™•μž₯ ν•¨μˆ˜μ™€ ν”„λ‘œνΌν‹°λ₯Ό μ •μ˜ν•  수 μžˆλ‹€.

class Person(val name: String) {
    companion object Loader { //λ™λ°˜ 객체에 이름을 뢙인닀.
        fun fromJSON(jsonText: String): Person = ...
    }
}

//μ ‘κ·Όν•  λ•Œ
Person.Loader.fromJSON(...)

 

  • λ™λ°˜ κ°μ²΄μ—μ„œ μΈν„°νŽ˜μ΄μŠ€ κ΅¬ν˜„
interface JSONFactory<T> {
    fun fromJSON(jsonText: String): T
}

class Person(val name: String) {
    companion object : JSONFactory<Person> {
        //...
    }
}

λ™λ°˜ 객체의 μΈμŠ€ν„΄μŠ€λ₯Ό 전달할 μˆ˜λ„ μžˆλ‹€.

fun loadFromJSON<T>(factory: JSONFactory<T>): T {
    //...
}

loadFromJSON(Person) //μΈμŠ€ν„΄μŠ€λ₯Ό λ„˜κΈΈ λ•Œ Person 클래슀(λ™λ°˜ 객체λ₯Ό κ°μ‹ΈλŠ” 클래슀)의 μ΄λ¦„μœΌλ‘œ λ„˜κΈ΄λ‹€.

 

  • λ™λ°˜ 객체 ν™•μž₯

ν΄λž˜μŠ€μ— λ™λ°˜ 객체가 있으면 κ·Έ 객체 μ•ˆμ— ν•¨μˆ˜λ₯Ό μ •μ˜ν•¨μœΌλ‘œμ¨ ν΄λž˜μŠ€μ— λŒ€ν•΄ ν˜ΈμΆœν•  수 μžˆλŠ” ν™•μž₯ ν•¨μˆ˜λ₯Ό λ§Œλ“€ 수 μžˆλ‹€.

 

객체 식: 무λͺ… λ‚΄λΆ€ 클래슀λ₯Ό λ‹€λ₯Έ λ°©μ‹μœΌλ‘œ μž‘μ„±

무λͺ… 객체(anonymous object)λ₯Ό μ •μ˜ν•  λ•Œλ„ object ν‚€μ›Œλ“œλ₯Ό μ“΄λ‹€.

window.addMouseListener(
    object : MouseAdapter() {
        override fun mouseClicked(e: MouseEvent) {
            // ...
        }

        override fun mouseEntered(e: MouseEvent) {
            // ...
        }
    }
}

 

객체에 이름을 λΆ™μ—¬μ•Ό ν•œλ‹€λ©΄ λ³€μˆ˜μ— 무λͺ… 객체λ₯Ό λŒ€μž…ν•˜λ©΄ λœλ‹€.
μ½”ν‹€λ¦°μ˜ 무λͺ… ν΄λž˜μŠ€λŠ” μ—¬λŸ¬ μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜κ±°λ‚˜ 클래슀λ₯Ό ν™•μž₯ν•˜λ©΄μ„œ μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•  수 μžˆλ‹€.

 

무λͺ… κ°μ²΄λŠ” 싱글턴이 μ•„λ‹ˆλ‹€.

 

μžλ°”μ™€ 달리 final이 μ•„λ‹Œ λ³€μˆ˜λ„ 객체 식 μ•ˆμ—μ„œ μ‚¬μš©ν•  수 μžˆλ‹€.