(1) Kotlin의 object
코틀린에서의 object 키워드는 두가지 형태로 사용 할 수 있다.
- object declarations(선언식)
- object expressions(표현식)
1. object declarations(선언식) : Singleton
object를 선언식으로 사용하게 된다면 Singleton 형태로 사용할 수 있다.
코틀린에서 object를 선언식으로 사용하는 문법은 다음과 같다.
object Singleton {
...
}
본 코틀린 코드를 자바로 디컴파일 해보면 다음과 같다.
public final class Singleton {
public static final Singleton INSTANCE;
static {
Singleton var0 = new Singleton();
INSTANCE = var0;
}
}
디컴파일 결과에서 보이는 것과 같이, Singleton 형태로 변환 되는 것을 볼 수 있다.
object 내에 class와 같이 멤버 변수 / 메서드를 가질 수 있으며, class 및 interface의 상속이 가능하다.
따라서, object를 선언식으로 사용하게 되면 자바의 Singleton 패턴과 같이 객체를 생성하여 사용할 수 있다.
object Singleton : MyClass(), MyInterface { // class, interface 상속 가능
private val name: String = "Hunseong" // 멤버 변수
override fun hi() {
...
}
}
2. object expressions(표현식) : Non-Singleton
선언식과 달리 object를 표현식으로 사용하면 Singleton의 형태로 사용하지 않는다.
주로 다음과 같은 형태로 사용한다.
1. 익명 클래스의 객체를 바로 생성하고자 할 때
2. 추상클래스, 인터페이스의 구현체를 익명 클래스의 객체로 구현하고자 할 때
// 1. 익명 클래스의 객체를 바로 생성하고자 할 때
val user = object {
val name = "hunseong"
val age = 24
}
println(user.name) // hunseong
println(user.age) // 24
// 2. 추상클래스, 인터페이스의 구현체를 익명 클래스의 객체로 구현하고자 할 때
val myListener: MyInterface = object : MyListener {
//implement interface
}
user.addListener(myListener)
user2.addListner(object : MyListener {
//implement interface
})
(2) Java의 static
Java에는 static 키워드를 통해 클래스의 인스턴스를 생성하지 않고도 변수, 메서드를 사용할 수 있다.
이러한 static 키워드를 통해 선언된 변수, 메서드를 각각 클래스 변수, 클래스 메서드라 한다.
public final class User {
static public final String TAG = "user_tag"; // 클래스 변수
static public plusOne(int num):int {
return num + 1
}
}
// 클래스의 인스턴스를 생성하지 않고 호출 가능
// User.TAG
// User.plusOne(10)
안드로이드에서 이러한 static(정적) 변수, 메서드는 다음과 같은 용도로 많이 쓰인다.
1. 클래스 / 프래그먼트의 Intent Extra Key
2. 클래스 / 프래그먼트의 고유한 tag 값 등 상수
3. 다양한 유틸리티용 메서드
그러나 코틀린의 경우에는 static 키워드가 존재하지 않는다.
대신 자바의 static 키워드와 매우 유사하게 사용 할 수 있는 companion object (동반 객체)가 존재한다.
(3) Kotlin에서의 static 대체, companion object
- companion object (동반 객체)는 이름 그대로 클래스 내부에 존재하며, 클래스가 메모리에 적재될 때 함께 생성된다.
- 동반 객체라는 이름답게, 클래스 별 하나의 companion object만을 둘 수 있다.
- object와 같이 클래스, 인터페이스를 상속 받을 수 있다.
- Outer class는 companion object에 접근 가능하나, companion object 내에서는 Outer class에 접근할 수 없다.
- 별도 클래스의 인스턴스를 생성하지 않고 클래스명으로 접근하여 자바의 static 변수, 메소드처럼 사용할 수 있다.
- 클래스명.Companion 으로 접근 할 수 있으며, 변수에 할당이 가능하다.
class User {
companion object {
val TAG = "user_tag"
fun logName(name: String) {
Log.d(TAG, "user name : $name")
}
}
}
println(User.TAG) // user_tag
User.logName("hunseong") // log - user name : hunseong
val userObject = User.Companion
println(User.Companion.TAG) // user_tag
println(userObject.TAG) // user_tag
- companion object에도 이름을 지정할 수 있다. 이 때는 클래스명.이름 으로 접근 할 수 있다.
class User {
companion object Hi {
val TAG = "user_tag"
fun logName(name: String) {
Log.d(TAG, "user name : $name")
}
}
}
println(User.Hi.TAG) // user_tag
User.Hi.logName("hunseong") // log - user name : hunseong
그렇다면 자바의 static과 동일할까? 그렇지 않다.
위에 빨간색으로 강조한 부분이 있는데, 클래스명.Companion 으로 접근 할 수 있으며, 변수에 할당이 가능하다.
즉, companion object는 static과 달리 객체로써 생성이 된다는 것이다.
해당 코드를 자바로 디컴파일하면 다음과 같다.
public final class User {
@NotNull
private static final String TAG = "user_tag";
@NotNull
public static final User.Companion Companion = new User.Companion((DefaultConstructorMarker)null);
public static final class Companion {
@NotNull
public final String getTAG() {
return User.TAG;
}
public final void logName(@NotNull String name) {
Intrinsics.checkNotNullParameter(name, "name");
Log.d(((User.Companion)this).getTAG(), "user name : " + name);
}
private Companion() {
}
// $FF: synthetic method
public Companion(DefaultConstructorMarker $constructor_marker) {
this();
}
}
}
}
디컴파일 결과로 알 수 있듯이, User class 내부에 Companion이라는 클래스가 있으며, 해당 Companion 객체를 생성한다.
Companion 클래스만 static으로 되어 있으며, Companion 클래스 내부의 변수, 메서드는 static 형태로 존재하지 않는다.
그럼 companion object의 변수, 메서드는 영영 static이 될 수 없는걸까.
해당 companion object 내 변수, 메서드에 각각 @JvmField, @JvmStatic 어노테이션을 붙이면 static 키워드가 붙으므로
Java의 static 변수, 메서드와 같이 사용 할 수 있다.
companion object의 경우 클래스와 연관된 값들을 자바의 static과 같이 활용하면 유용할 것이다.
출처 : https://www.bsidesoft.com/8187
https://www.androidhuman.com/2016-07-10-kotlin_companion_object
'Kotlin' 카테고리의 다른 글
Reactive Programming (0) | 2021.12.22 |
---|---|
[Android, Kotlin] 제네릭의 in, out 키워드는 무엇일까? (9) | 2021.11.28 |
[Kotlin] Class, Interface 새로 배운 학습 정리 (0) | 2021.11.12 |
[Kotlin] Type, String, Array 새로 배운 학습 정리 (0) | 2021.11.12 |
[Android, Kotlin] apply, also, let, with, run의 사용 - 범위 지정 함수 (0) | 2021.11.11 |