하위 클래스를 만들지 않고 특정 클래스를 일부 수정해서 객체를 만들려면 자바에선 익명 클래스를 이용했다. 코틀린은 오브젝트 식과 오브젝트 선언으로 할 수 있다.
오브젝트 식
사용은 다음과 같다.
open class A() {
open fun printA()
}
val ab = object : A() {
override fun printA() {
...
}
}
만약 상위 타입이 생성자를 가지면 알맞은 패러미터를 전달하면 된다. 여러개 상속할 경우 콤마로 구분 지을 수 있다.
open class A(x: Int) {
open val b = x
}
interface B {...}
val ab = object : A(2), B {
override val b = 15
}
단순 객체만 필요하면 상속받지 않으면 된다.
fun foo(){
val ad = object{
var x = 0
var y = 0
}
print(ad.x + ad.y)
}
익명 객체는 로컬과 private 선언에서만 타입으로 사용할 수 있다. public 함수나 프로퍼티의 타입으로 익명 객체를 사용하면, 함수나 프로퍼티의 실제 타입은 익명 객체에 선언한 상위 타입이 된다. 상위 타입을 선언하지 않았다면 Any 가 된다. 또한 public 타입으로 선언하면 멤버에 접근하지 못한다.
class C{
private fun foo() = object {
val x = "x"
}
fun publicFoo() = object {
val x = "x"
}
fun bar() {
val x1 = foo().x
val x2 = publicFoo().x //Unresolved reference: x
}
}
오브젝트 식의 코드는 둘러싼 범위의 변수에 접근 가능하고 자바와 달리 final변수로 제한되지 않는다.
오브젝트 선언
오브젝트 키워드로 오브젝트 선언을 할 수 있다. 코틀린을 이를 이용해서 싱글톤을 쉽게 선언할 수 있다.
object MySingleTon {
fun printP(msb: String){
print(msb)
}
}
이 오브젝트를 참조하려면 객체를 생성하는 것이 아닌 오브젝트 이름을 사용한다.
MySingleTon.printP("test")
이러한 오브젝트 선언은 객체를 생성이 아닌 할당할 수 있다.
fun main() {
val a = MySingleTon
val b = MySingleTon
val c = MyPublic()
val d = MyPublic()
println(" a : $a")
println(" b : $b")
println(" c : $c")
println(" d : $d")
}
object MySingleTon {
fun printP(msg: String) {
print(msg)
}
}
class MyPublic() {}
출력결과
----
a : MySingleTon@511baa65
b : MySingleTon@511baa65
c : MyPublic@340f438e
d : MyPublic@30c7da1e
보면 주소가 같다.
오브젝트는 상위 타입을 가질 수 있다.
object Listener : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) { ... }
override fun mouseEntered(e: MouseEvent) { ... }
}
컴페니언 오브젝트
클래스 내부의 오브젝트 선언은 companion 키워드를 붙일 수 있다.
class MyClass {
companion object Factory {
fun create(): MyClass = MyClass()
}
}
컴페니언 오브젝트의 멤버는 클래스 이름을 한정자로 호출할 수 있다.
val instance = MyClass.create()
또한 컴페니언 오브젝트의 이름은 생략 가능하며 생략할 경우 이름으로 Companion를 사용한다.
val instance = Myclass.Companion
컴페니언 오브젝트는 다른 언어의 정적 멤버처럼 보이지만, 런타임에 실제 객체의 인스턴스이므로 인터페이스를 구현할 수 있다.
interface Factory<T> {
fun create(): T
}
class MyClass {
companion object : Factory<MyClass> {
override fun create(): MyClass = MyClass()
}
}
JVM에서 @JvmStatic
어노테이션을 사용하면 컴페니언 오브젝트의 멤버를 실제 정적 메서드와 필드로 생성한다.
의미 차이
3가지가 있다.
- 오브젝트 식은 사용한 위치에서 즉시 초기화 되고 실행된다.
- 오브젝트 선언은 처음 접근할 때까지 초기화를 지연한다.
- 컴페니언 오브젝트는 대응하는 클래스를 로딩할 때 초기화된다. 이는 자바의 정적 초기화와 동일하다.
'코틀린' 카테고리의 다른 글
16. 코루틴 기본 (0) | 2022.06.13 |
---|---|
15. 인라인 함수 (0) | 2022.06.13 |
14. 고차함수와 람다 (0) | 2022.06.12 |
13. 함수 (0) | 2022.06.12 |
12. 위임 (0) | 2022.06.12 |