Object
Kotlin에서 object는 두가지 형태로 나뉜다.
- Object Declarations (객체 선언식)
- Object Expressions (객체 표현식)
Object Declarations
Kotlin에서는 Java와 다르게 Singleton Class를 사용하기 위에 Object Declarations(객체 선언)을 사용한다.
Java에서는 아래 코드처럼 보통 클래스의 constructor를 private으로 선언하고, statice 변수에 클래스 객체를 저장하는 방식으로 싱글턴 패턴을 구현한다.
public class Manager {
private static Singleton INSTANCE;
private Manager() { }
public static Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Manager();
}
return INSTANCE;
}
}
Kotlin에서는 객체 선언 (object) 기능을 통해 싱글턴을 언어 자체에서 기본지원 한다.
object Manager{
}
위 코드를 Java로 Decompile 해보면 아래와 같다.
Singleton 형태로 변환 되어 있다.
public final class Manager {
@NotNull
public static final Manager INSTANCE;
private Manager() {
}
static {
Manager var0 = new Manager();
INSTANCE = var0;
}
}
object Manager: TestClass(), ApiInterface {
private val name: String = "Bumjae"
override fun TestClassTodo(){
...
}
}
object 내에 class와 같이 멤버 변수 / 메서드를 가질 수 있으며, class 및 interface의 상속이 가능하다.
따라서, object를 선언식으로 사용하게 되면 자바의 Singleton 패턴과 같이 객체를 생성하여 사용할 수 있다.
Object Expressions
표현식 object는 선언식과 달리 Singleton의 형태로 사용하지 않는다.
호출할 때 마라 새로운 인스턴스가 생성되고, 익명 클래스 안에서 자신이 포함된 함수의 로컬 변수에 접근할 수 있다.
주로 다음과 같은 형태로 사용한다.
- 익명 클래스의 객체를 바로 생성하고자 하는 경우
fun main() {
val user = object{
val name = "Bumjae"
val age = 28
}
println(user.name)
println(user.age)
}
- 추상클래스, 인터페이스의 구현체를 익명 클래스의 객체로 구현하고자 하는 경우
interface MyInterface{
val name:String
val age: Int
fun greeting()
}
val myListener= object: MyInterface{
override val name = "Bumjae"
override val age = 28
override fun greeting(){
println("my name is ${name}")
println("and I'm ${age} years old!")
}
}
fun main() {
myListener.greeting()
}
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)
그러나 Kotlin의 경우에는 static 키워드가 존재하지 않는다.
대신 Java의 static 키워드와 매우 유사하게 사용 할 수 있는 companion object (동반 객체)가 존재한다.
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 printName(name: String) {
println("$TAG user name : $name")
}
}
}
fun main(){
println(User.TAG)
User.printName("bumajae")
val userObject = User.Companion
println(userObject.TAG)
}
Java의 static과 동일한가?
위에 강조한 부분으로 클래스명.Companion 으로 접근 할 수 있으며, 변수에 할당이 가능하다는 점인데 이 말은 companion object는 static과 달리 객체로써 생성된다는 것이다.
위 코드를 Java로 Decompile 해보면 User class 내부에 Companion이라는 클래스가 있으며, 해당 Companion 객체를 생성한다.
Companion 클래스만 static으로 되어 있으며, Companion 클래스 내부의 변수, 메서드는 static 형태로 존재하지 않는다.
public final class User {
@NotNull
private static final String TAG = "user_tag";
@NotNull
public static final Companion Companion = new Companion((DefaultConstructorMarker)null);
public static final class Companion {
@NotNull
public final String getTAG() {
return User.TAG;
}
public final void printName(@NotNull String name) {
Intrinsics.checkNotNullParameter(name, "name");
String var2 = ((Companion)this).getTAG() + " user name : " + name;
System.out.println(var2);
}
private Companion() {
}
// $FF: synthetic method
public Companion(DefaultConstructorMarker $constructor_marker) {
this();
}
}
}
만약 static이 되게 하고 싶으면 companion object 내 변수, 메서드에 각각 @JvmField, @JvmStatic 어노테이션을 붙이면 static 키워드가 붙으므로 Java의 static 변수, 메서드와 같이 사용 할 수 있다.
Object vs Companion Object
Object declaration | companion object |
Class 전체가 하나의 Singleton 으로 선언 | Class 내 일부분이 Singleton으로 선언 |
해당 Class가 사용될 때 초기화 | 해당 Class가 로드 될 때 초기화 |
Reference
https://parade621.tistory.com/37
https://medium.com/@lunay0ung/kotlin-object-declaration-그리고-companion-object-feat-static-d5c97c21168
https://www.androidhuman.com/2016-07-10-kotlin_companion_object
'Kotlin > Basic' 카테고리의 다른 글
Kotlin DSL, buildSrc 의존성 주입 (0) | 2023.12.07 |
---|---|
Stream Fuction (0) | 2022.03.14 |
Closure, Scope Function (let, also, run, apply, with) (0) | 2022.03.11 |
Coroutine (0) | 2022.01.17 |