티스토리 뷰
본 포스팅의 내용은 [깡샘의 코틀린 프로그래밍]을 공부하고 작성자가 생각을 정리하기 위해서 작성한 글이므로 더욱 자세한 내용을 알고 싶으신 분은 [깡샘의 코틀린 프로그래밍]을 강력 추천합니다!!
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 클래스
- 이름이 없다.
- 선언과 동시에 생성하게 된다.
- 생성자가 없으므로 처음 생성되는 객체 이외에 생성할 수 없다.
참고 자료
[깡샘의 코틀린 프로그래밍] 강성윤 지음 <루비페이퍼>
반응형
'Programming > 코틀린(Kotlin)' 카테고리의 다른 글
[코틀린] 14. 컬렉션 타입과 람다 - 1. 집합 연산 함수 (0) | 2021.05.02 |
---|---|
[코틀린] 코틀린 API의 범위 지정 함수 (0) | 2021.04.26 |
[코틀린] 10. 추상 클래스와 인터페이스 (feat. 깡샘) (0) | 2021.04.12 |
추상 클래스와 인터페이스의 사용 목적 (0) | 2021.04.12 |
[코틀린] 09. 상속 (feat. 깡샘) (0) | 2021.04.12 |
댓글