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

Android & Kotlin

[๋‚ด๋ณด๋‚ด๋ฒˆ] Classes | Kotlin

Kotlin์„ ๊ณต๋ถ€ํ•˜๋ฉด์„œ ์ƒ์†์— ๋Œ€ํ•œ ๋ถ€๋ถ„์„ ๊ณต๋ถ€ํ•˜๊ณ ์ž ๊ณต์‹ ๋ฌธ์„œ๋ฅผ ์ง์ ‘ ๋ฒˆ์—ญํ–ˆ๋‹ค.
ํ•ด๋‹น ๋ฌธ์„œ๋Š” 2022๋…„ 3์›” 3์ผ์ž ๊ณต์‹ ๋ฌธ์„œ์ด๋‹ค.

Kotlin ๊ณต์‹๋ฌธ์„œ ํ™•์ธํ•˜๊ธฐ โžก๏ธ

 

Classes | Kotlin

 

kotlinlang.org

 

โ€ป ์˜์–ด ์ „๊ณต์ž๋„ ํ•ด์™ธ ์œ ํ•™ํŒŒ๋„ ์•„๋‹ˆ๊ธฐ์— ๋ฒˆ์—ญ์—๋Š” ์˜์—ญ, ์˜ค์—ญ, ๊ตฌ๊ธ€ ๋ฒˆ์—ญ์ด ๋ฌด์ˆ˜ํžˆ ๋งŽ์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ํ˜ผ์ž ๊ณต์‹๋ฌธ์„œ๋ฅผ ์ฐธ์กฐํ•ด๊ฐ€๋ฉฐ ๋ฒˆ์—ญํ•˜๋‹ค ๋ณด๋‹ˆ ์˜คํƒ€๋„ ๋งŽ์„ ์ˆ˜ ์žˆ๋‹ค. ์ •ํ™•ํ•œ ๋‚ด์šฉ์€ ๊ณต์‹๋ฌธ์„œ๋ฅผ ์ง์ ‘ ์‚ดํŽด๋ณด๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ์ •๋ณด๋“ค์„ ๋” ์ฐพ์•„๋ณด๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•œ๋‹ค.

(ํ•˜์ง€๋งŒ ๋Œ“๊ธ€ ํ”ผ๋“œ๋ฐฑ๋„ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค๐Ÿ˜ƒ )

 

Classes in Kotlin are declared using the keyword class:

์ฝ”ํ‹€๋ฆฐ์˜ ํด๋ž˜์Šค๋Š” class ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„ ์–ธ๋œ๋‹ค:

class Person { /*...*/ }
 

The class declaration consists of the class name, the class header (specifying its type parameters, the primary constructor, and some other things), and the class body surrounded by curly braces. Both the header and the body are optional; if the class has no body, the curly braces can be omitted.

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

class Empty
 

 

Constructors

A class in Kotlin can have a primary constructor and one or more secondary constructors. The primary constructor is a part of the class header, and it goes after the class name and optional type parameters.

์ฝ”ํ‹€๋ฆฐ์—์„œ ํด๋ž˜์„œ๋Š” ํ•˜๋‚˜์˜ ๊ธฐ๋ณธ ์ƒ์„ฑ์ž์™€ ํ•˜๋‚˜๋‚˜ ๊ทธ ์ด์ƒ์˜ ๋ณด์กฐ ์ƒ์„ฑ์ž๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค. ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๋Š” ํด๋ž˜์Šค ํ—ค๋”์˜ ์ผ๋ถ€๋ถ„์ด๊ณ  ํด๋ž˜์Šค ์ด๋ฆ„๊ณผ ์„ ํƒ์ ์œผ๋กœ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋Š” ํƒ€์ž… ํŒŒ๋ผ๋ฏธํ„ฐ ๋’ค์— ์˜จ๋‹ค. 

class Person constructor(firstName: String) { /*...*/ }
 

If the primary constructor does not have any annotations or visibility modifiers, the constructor keyword can be omitted:

๋งŒ์ผ ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๊ฐ€ ์–ด๋– ํ•œ ์–ด๋…ธํ…Œ์ด์…˜์ด๋‚˜ ๋ˆˆ์— ๋ณด์ด๋Š” modifier ํ‚ค์›Œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์ง€ ์•Š๋‹ค๋ฉด constructor ํ‚ค์›Œ๋“œ๋Š” ์ƒ๋žต๊ฐ€๋Šฅํ•˜๋‹ค:

class Person(firstName: String) { /*...*/ }
 

The primary constructor cannot contain any code. Initialization code can be placed in initializer blocks prefixed with the init keyword.

๊ธฐ๋ณธ ์ƒ์„ฑ์ž๋Š” ์–ด๋– ํ•œ ์ฝ”๋“œ๋„ ํฌํ•จํ•  ์ˆ˜ ์—†๋‹ค. ์ดˆ๊ธฐํ™” ์ฝ”๋“œ๋Š” init์ด๋ผ๋Š” ํ‚ค์›Œ๋“œ๊ฐ€ ์ ‘๋‘์‚ฌ๋กœ ๋ถ™์€ ์ดˆ๊ธฐํ™” ๋ธ”๋Ÿญ์— ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. 

During the initialization of an instance, the initializer blocks are executed in the same order as they appear in the class body, interleaved with the property initializers:

๐Ÿ‘€์ธ์Šคํ„ด์Šค๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๋™์•ˆ ์ดˆ๊ธฐํ™” ๋ธ”๋Ÿญ๋“ค์€ ์†์„ฑ ์ดˆ๊ธฐํ™”๊ฐ€ ์‚ฌ์ด์— ๋“ค์–ด๊ฐ„ ํด๋ž˜์Šค ๋ฐ”๋””์— ๋‚˜ํƒ€๋‚œ ์ˆœ์„œ์™€ ์ผ์น˜ํ•˜๊ฒŒ ์‹คํ–‰๋œ๋‹ค:

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

Primary constructor parameters can be used in the initializer blocks. They can also be used in property initializers declared in the class body:

๊ธฐ๋ณธ ์ƒ์„ฑ์ž์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋“ค์€ ์ดˆ๊ธฐํ™” ๋ธ”๋Ÿญ์—์„œ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋‹ค. ์ด๊ฒƒ๋“ค์€ ๋˜ํ•œ ํด๋ž˜์Šค ๋ฐ”๋””์— ์„ ์–ธ๋œ ์†์„ฑ ์ดˆ๊ธฐํ™”์—์„œ๋„ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋‹ค. 

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

Kotlin has a concise syntax for declaring properties and initializing them from the primary constructor:

์ฝ”ํ‹€๋ฆฐ์€ ์†์„ฑ์„ ์„ ์–ธํ•˜๊ณ  ๊ธฐ๋ณธ ์ƒ์„ฑ์ž์—์„œ ์ดˆ๊ธฐํ™”ํ•˜๊ธฐ ์œ„ํ•œ ์ถ•์•ฝ๋œ ๋ฌธ๋ฒ•์„ ๊ฐ–๊ณ  ์žˆ๋‹ค. 

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

Such declarations can also include default values of the class properties:

์ด์™€ ๊ฐ™์€ ์„ ์–ธ์—๋Š” ํด๋ž˜์Šค ์†์„ฑ์˜ ๊ธฐ๋ณธ๊ฐ’๋„ ํฌํ•จ๋  ์ˆ˜ ์žˆ๋‹ค: 

class Person(val firstName: String, val lastName: String, var isEmployed: Boolean = true)
 

You can use a trailing comma when you declare class properties:

ํ›„ํ–‰ ์‰ผํ‘œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํด๋ž˜์Šค ์†์„ฑ์„ ์„ ์–ธํ•  ์ˆ˜ ์žˆ๋‹ค:

class Person(
    val firstName: String,
    val lastName: String,
    var age: Int, // trailing comma
) { /*...*/ }
 

Much like regular properties, properties declared in the primary constructor can be mutable (var) or read-only (val).

๋ณดํ†ต์˜ ์†์„ฑ๊ณผ ๊ฐ™์ด ๊ธฐ๋ณธ ์ƒ์„ฑ์ž์— ์„ ์–ธ๋œ ์†์„ฑ์€ ๊ฐ€๋ณ€์ ์ผ์ˆ˜๋„ (var) ์ฝ๊ธฐ ์ „์šฉ(val)์ผ ์ˆ˜๋„ ์žˆ๋‹ค.

If the constructor has annotations or visibility modifiers, the constructor keyword is required and the modifiers go before it:

์ƒ์„ฑ์ž์— ์–ด๋…ธํ…Œ์ด์…˜์ด๋‚˜ ๋ˆˆ์— ๋ณด์ด๋Š” modifier๊ฐ€ ์žˆ๋‹ค๋ฉด constructor ํ‚ค์›Œ๋“œ๊ฐ€ ์š”๊ตฌ๋˜๊ณ  modifier๋Š” ๊ทธ ์ „์— ์˜จ๋‹ค: 

class Customer public @Inject constructor(name: String) { /*...*/ }
 

Learn more about visibility modifiers.

visibility modifiers์— ๋Œ€ํ•ด ๋” ๋ฐฐ์›Œ๋ณด๊ธฐ.

 

Secondary constructors

A class can also declare secondary constructors, which are prefixed with constructor:

ํด๋ž˜์Šค๋Š” 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
    }
}
 

If the class has a primary constructor, each secondary constructor needs to delegate to the primary constructor, either directly or indirectly through another secondary constructor(s). Delegation to another constructor of the same class is done using the this keyword:

ํด๋ž˜์Šค์— ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๊ฐ€ ์žˆ๋‹ค๋ฉด ๊ฐ ๋ณด์กฐ ์ƒ์„ฑ์ž๋Š” ์ง์ ‘์ ์œผ๋กœ๋‚˜ ๋‹ค๋ฅธ ๋ณด์กฐ ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด ๊ฐ„์ ‘์ ์œผ๋กœ ๊ธฐ๋ณธ ์ƒ์„ฑ์ž์— ์œ„์ž„ํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค.

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

Code in initializer blocks effectively becomes part of the primary constructor. Delegation to the primary constructor happens as the first statement of a secondary constructor, so the code in all initializer blocks and property initializers is executed before the body of the secondary constructor.

์ดˆ๊ธฐํ™” ๋ธ”๋Ÿญ์˜ ์ฝ”๋“œ๋Š” ํšจ๊ณผ์ ์œผ๋กœ ๊ธฐ๋ณธ ์ƒ์„ฑ์ž์˜ ์ผ๋ถ€๋ถ„์ด ๋œ๋‹ค. ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๋กœ์˜ ์œ„์ž„์€ ๋ณด์กฐ ์ƒ์„ฑ์ž์˜ ์ฒซ๋ฒˆ์งธ ๊ตฌ๋ฌธ์—์„œ ๋ฐœ์ƒํ•˜์—ฌ ์ดˆ๊ธฐํ™” ๋ธ”๋Ÿญ์˜ ๋ชจ๋“  ์ฝ”๋“œ์™€ ์†์„ฑ ์ดˆ๊ธฐํ™”๋Š” ๋ณด์กฐ ์ƒ์„ฑ์ž์˜ ๋ฐ”๋”” ์ „์— ์‹คํ–‰๋œ๋‹ค. 

Even if the class has no primary constructor, the delegation still happens implicitly, and the initializer blocks are still executed:

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

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

    constructor(i: Int) {
        println("Constructor $i")
    }
}

fun main() {
    Constructors(1)
}
Init block
Constructor 1

If a non-abstract class does not declare any constructors (primary or secondary), it will have a generated primary constructor with no arguments. The visibility of the constructor will be public.

๋น„์ถ”์ƒ ํด๋ž˜์Šค๊ฐ€ ์–ด๋– ํ•œ ์ƒ์„ฑ์ž(๊ธฐ๋ณธ์ด๋‚˜ ๋ณด์กฐ)๋„ ์„ ์–ธํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ์ธ์ž๊ฐ€ ์—†๋Š” ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๋ฅผ ์ƒ์„ฑํ•  ๊ฒƒ์ด๋‹ค. ์ƒ์„ฑ์ž์˜ visibility๋Š” public์ด ๋œ๋‹ค.

If you don't want your class to have a public constructor, declare an empty primary constructor with non-default visibility:

ํด๋ž˜์Šค๊ฐ€ public ์ƒ์„ฑ์ž๋ฅผ ๊ฐ–๊ธฐ ์›ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ๊ธฐ๋ณธ์˜ visibility๊ฐ€ ์•„๋‹Œ ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๋ฅผ ์„ ์–ธํ•˜๋ผ:

class DontCreateMe private constructor () { /*...*/ }
 

On the JVM, if all of the primary constructor parameters have default values, the compiler will generate an additional parameterless constructor which will use the default values. This makes it easier to use Kotlin with libraries such as Jackson or JPA that create class instances through parameterless constructors.

JVM์—์„œ ๋ชจ๋“  ๊ธฐ๋ณธ ์ƒ์„ฑ์ž์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ๊ธฐ๋ณธ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋ฉด ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ๊ธฐ๋ณธ๊ฐ’์„ ์‚ฌ์šฉํ•  ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์—†๋Š” ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๋ฅผ ์ถ”๊ฐ€์ ์œผ๋กœ ์ƒ์„ฑํ•  ๊ฒƒ์ด๋‹ค. ์ด๋ฅผ ํ†ตํ•ด Jackson์ด๋‚˜ JPA๊ฐ™์ด ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์—†๋Š” ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ํ•จ๊ป˜ ์ฝ”ํ‹€๋ฆฐ์„ ๋” ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•˜๊ฒŒ ํ•ด์ค€๋‹ค. 

class Customer(val customerName: String = "")

 

Creating instances of classes

To create an instance of a class, call the constructor as if it were a regular function:

ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋ ค๋ฉด ๋ณดํ†ต์˜ ํ•จ์ˆ˜์ธ ๊ฒƒ ๊ฐ™์ด ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•˜๋ผ:

val invoice = Invoice()

val customer = Customer("Joe Smith")
 

Kotlin does not have a new keyword.
์ฝ”ํ‹€๋ฆฐ์€ new ํ‚ค์›Œ๋“œ๊ฐ€ ์—†๋‹ค.

The process of creating instances of nested, inner, and anonymous inner classes is described in Nested classes.

์ค‘์ฒฉ๋œ, ๋‚ด๋ถ€์˜ ๊ทธ๋ฆฌ๊ณ  ๋ฌด๋ช…์˜ ๋‚ด๋ถ€ ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ณผ์ •์€ Nested classes ์— ๊ธฐ์ˆ ๋˜์–ด ์žˆ๋‹ค. 

 

Class members

Classes can contain:

ํด๋ž˜์Šค๋Š” ๋‹ค์Œ์„ ํฌํ•จํ•  ์ˆ˜ ์žˆ๋‹ค:

  • ์ƒ์„ฑ์ž์™€ ์ดˆ๊ธฐํ™” ๋ธ”๋Ÿญ
  • ํ•จ์ˆ˜
  • ์†์„ฑ
  • ์ค‘์ฒฉ ๋ฐ ๋‚ด๋ถ€ ํด๋ž˜์Šค
  • ๊ฐ์ฒด ์„ ์–ธ

 

Inheritance

Classes can be derived from each other and form inheritance hierarchies. Learn more about inheritance in Kotlin.

ํด๋ž˜์Šค๋Š” ์„œ๋กœ๋กœ๋ถ€ํ„ฐ ํŒŒ์ƒ๋  ์ˆ˜ ์žˆ๊ณ  ์ƒ์† ๊ณ„์ธต๊ด€๊ณ„๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. ์ฝ”ํ‹€๋ฆฐ์˜ ์ƒ์†์— ๋Œ€ํ•ด์„œ ๋” ์•Œ์•„๋ณด๋ผ. 

 

Abstract classes

A class may be declared abstract, along with some or all of its members. An abstract member does not have an implementation in its class. You don't need to annotate abstract classes or functions with open.

ํด๋ž˜์Šค๋Š” ๋ช‡๋ช‡ ํ˜น์€ ์ „์ฒด์˜ ๋ฉค๋ฒ„์™€ ํ•จ๊ป˜ ์ถ”์ƒ์œผ๋กœ ์„ ์–ธ๋  ์ˆ˜ ์žˆ๋‹ค. ์ถ”์ƒ ๋ฉค๋ฒ„๋Š” ํ•ด๋‹น ํด๋ž˜์Šค์— ๊ตฌํ˜„๋˜์–ด ์žˆ์ง€ ์•Š๋‹ค. ์ถ”์ƒ ํด๋ž˜์Šค์— ๋Œ€ํ•ด ์–ด๋…ธํ…Œ์ด์…˜์„ ๋‹ฌ๊ฑฐ๋‚˜ ํ•จ์ˆ˜๋ฅผ open์œผ๋กœ ํ‘œ์‹œํ•ด๋‘˜ ํ•„์š”๊ฐ€ ์—†๋‹ค. 

abstract class Polygon {
    abstract fun draw()
}

class Rectangle : Polygon() {
    override fun draw() {
        // draw the rectangle
    }
}
 

You can override a non-abstract open member with an abstract one.

์ถ”์ƒ์ด ์•„๋‹Œ open ๋ฉค๋ฒ„๋ฅผ ์ถ”์ƒ์ ์ธ ๊ฒƒ์œผ๋กœ ์˜ค๋ฒ„๋ผ์ด๋“œ ํ•  ์ˆ˜ ์žˆ๋‹ค. 

open class Polygon {
    open fun draw() {
        // some default polygon drawing method
    }
}

abstract class WildShape : Polygon() {
    // Classes that inherit WildShape need to provide their own
    // draw method instead of using the default on Polygon
    abstract override fun draw()
}
 

 

Companion objects

If you need to write a function that can be called without having a class instance but that needs access to the internals of a class (such as a factory method), you can write it as a member of an object declaration inside that class.

๋งŒ์ผ ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค ์—†์ด ํ˜ธ์ถœ๋  ์ˆ˜ ์žˆ์ง€๋งŒ ํด๋ž˜์Šค์˜ ๋‚ด๋ถ€์—(factory ๋ฉ”์„œ๋“œ์™€ ๊ฐ™์ด) ์—‘์„ธ์Šค๊ฐ€ ํ•„์š”ํ•œ ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ํด๋ž˜์Šค ๋‚ด๋ถ€์— ๊ฐ์ฒด ์„ ์–ธ์˜ ๋ฉค๋ฒ„๋กœ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. 

Even more specifically, if you declare a companion object inside your class, you can access its members using only the class name as a qualifier.

๋” ๊ตฌ์ฒด์ ์œผ๋กœ ๋งํ•˜๋ฉด, ํด๋ž˜์Šค ๋‚ด๋ถ€์— companion ๊ฐ์ฒด๋ฅผ ์„ ์–ธํ•˜๋ฉด ํด๋ž˜์Šค ์ด๋ฆ„์„ ํ•œ์ •์ž๋กœ ์‚ฌ์šฉํ•  ๋•Œ๋งŒ ๊ทธ ๋ฉค๋ฒ„์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค. 

'Android & Kotlin' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[๋‚ด๋ณด๋‚ด๋ฒˆ] Interfaces | Kotlin  (0) 2022.03.03
[๋‚ด๋ณด๋‚ด๋ฒˆ] Properties | Kotin  (0) 2022.03.03
[๋‚ด๋ณด๋‚ด๋ฒˆ] Inheritance | Kotlin  (0) 2022.03.02
Overloading / Overriding  (0) 2022.03.02
Lesson 6: App Architecture (Persistence)  (0) 2022.02.23