티스토리 뷰

본 포스팅의 내용은 [깡샘의 코틀린 프로그래밍]을 공부하고 작성자가 생각을 정리하기 위해서 작성한 글이므로 더욱 자세한 내용을 알고 싶으신 분은 [깡샘의 코틀린 프로그래밍]을 강력 추천합니다!!


Object 클래스

0. 왜 굳이 익명 클래스를 정의할 필요가 있을까?

익명 클래스는 말 그대로 이름이 없는 클래스를 말한다.

근데 어떤 클래스를 선언하기는 해야 하는데 이 클래스의 객체를 여러 개 생성하지 않고 딱 한 번만 생성한다면 이름을 짓기가 귀찮기도 하고 코드를 지저분하게 만들 수 있기 때문이다.

이럴 때 이름 없는 클래스를 선언하고 바로 생성해서 이용한다.

 

1. obejct를 이용한 익명 내부 클래스 정의

  • object 예약어는 익명 클래스를 정의할 때 사용한다. 클래스 선언 때 class 예약어를 작성하지 않고 object { } 형태로 선언한다.
  • 선언과 동시에 객체가 생성된다.
val obj1 = object {
    var no: Int = 10
    fun myFun() {

    }
}
  • object 클래스에는 생성자를 추가할 수 없다.
class Outer {
    private var no: Int = 0

    // Outer 클래스에서 myInner의 멤버를 활용하려면 private 키워드를 추가해야 한다.
    private val myInner = object {
        val name: String = "weekyear"
        fun innerFun() {
            println("innerFun...")
            no++
        }
    }

    fun outerFun() {
        myInner.name
        myInner.innerFun()
    }
}

fun main(args: Array<String>) {
    val outer = Outer()
    outer.myInner.name // 에러 : 당연하지만 private으로 선언했기 때문에 활용할 수 없다.
    outer.myInner.innerFun() // 에러
}
  • object 클래스의 멤버들을 object 클래스 밖에서 활용하려면 private으로 선언해야 한다.
  • private으로 선언해야 Outer 클래스에서 이용할 수 있는 이유는 타입 때문이다. 모든 객체는 이용하려면 타입을 명시해야 한다.
  • private을 선언하지 않으면 Outer 외부에서도 접근할 수 있게 되는데 Outer 외부에서는 Outer 클래스 내의 object 클래스를 인지할 수 없다. 따라서 myInner 클래스는 Any 타입이 되므로 name이나 innerFun( )과 같은 멤버에 접근할 수 없게 된다.
  • 하지만, private으로 선언하면 내부에서만 사용하겠다는 의미이므로 object 타입 그대로 반환되기 때문에 Outer 내부에서는 name과 innerFun( )과 같은 멤버 사용이 가능하게 된다.

 

2. 타입 명시로 object 이용

  • 타입 명시를 하게 되면 private을 지정하지 않아도 외부에서 object 객체의 멤버를 이용할 수 있다.

 

3. object 선언

// 형식
val obj = object { }
// 클래스 이름이 있는 형식
val obj2 = object MyObject { }
  • 객체 생성이 클래스 선언과 동시에 이루어지므로 개발자가 코드로 생성하는 게 아닌 만큼, 생성자를 선언할 수 없다.
  • 결과적으로 object 클래스의 객체는 자동으로 생성되는 하나의 객체만 이용된다.
  • 위 특성 때문에 싱글턴 패턴을 구현하는데 object가 이용되기도 한다.

 

4. companion 예약어

class Outer {
    object NestedClass {
        val no: Int = 0
        fun myFun() {
            println("myFun...")
        }
    }
}

fun main(args: Array<String>) {
    val obj = Outer()
    obj.NestedClass.no // 에러

    Outer.NestedClass.no
    Outer.NestedClass.myFun()
}
  • 이름이 있는 object 클래스가 자바로 변형될 때는 static 예약어가 추가되어 static 멤버가 되기 때문에 객체(obj)로 접근하는 것이 아니라 클래스명(Outer)로 object 클래스의 멤버를 이용해야 한다.
  • companion은 object와 함께 사용되어 object 클래스의 멤버를 object 클래스명을 사용하지 않고 이용하게 해준다.
class Outer {
    companion object NestedClass {
        val no: Int = 0
        fun myFun() {
            println("myFun...")
        }
    }

    // Outer 클래스에서도 자신의 멤버 변수인 것처럼 사용 가능하다.
    fun myFun() {
        no
        myFun()
    }
}

fun main(args: Array<String>) {
    val obj = Outer()
    Outer.NestedClass.no
    Outer.NestedClass.myFun()

    Outer.no
    Outer.myFun()
}
  • object 클래스의 멤버를 외부에서 Outer 클래스의 멤버처럼 Outer.no와 같이 사용 가능하다.
  • Outer 클래스 내부에서도 본인의 클래스의 멤버처럼 이용할 수 있다
  • 즉, companion object를 이용하면 자바의 static과 같은 효과를 낼 수 있다.

왜 코틀린에서는 static 이라는 예약어를 제공하지 않을까?

  • 코틀린은 프로그램을 항상 클래스가 아니라 최상위에 변수나 함수를 얼마든지 선언할 수 있기 때문에 static이 필요 없기 때문이다.
  • 단일 메모리 구조에 저장되어야 하는 함수나 프로퍼티는 최상위에 선언하면 되기 때문이다.
  • 다만 클래스 내부에 선언한 멤버 중 객체 생성 없이 클래스명으로 직접 이용하고 싶을 때, 제공하는 것이 object 클래스나 companion object 클래스인 것이다.

 

5. Nested 클래스 vs. object 클래스

Nested 클래스

  • Nested 클래스는 특정 클래스 내부에 선언만 할 뿐 외부에 선언하는 것과 차이가 없다.
  • 하지만, Nested 클래스에서 외부 클래스의 멤버를 이용하려면 Nested 클래스 선언 때 inner라는 예약어를 추가해야 한다.
  • inner를 추가하면 inner가 추가된 클래스는 외부에서 객체로 생성할 수 없다.

Object 클래스

  • 이름이 없다.
  • 선언과 동시에 생성하게 된다.
  • 생성자가 없으므로 처음 생성되는 객체 이외에 생성할 수 없다.

 

참고 자료

[깡샘의 코틀린 프로그래밍] 강성윤 지음 <루비페이퍼>

반응형
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함