Kotlin 1.9.0 버전으로 올리면 Selad Class 자식으로 object 대신 data object를 사용하라고 권장합니다. 기존 object와 차이점은 무엇일까요? 어떤 장점이 있는 걸까요? 밑줄까지 치면서 권장하면서 말이에요
Stable data objects for symmetry with data classes
data object는 1.9.0 버전부터 정식 출시(Stable)된 데이터 홀더 객체입니다. 데이터 홀더 객체는 데이터를 저장하고 전달하고 표현하기 위한 목적을 가진 객체이에요. Kotlin은 이러한 데이터 홀더 객체를 사용하는 개발자들의 편리성을 위해 class를 대신 data class를 제공했고, data object는 object를 대체해서 나온 클래스라고 보시면 됩니다.
data object는 컴파일 시점에 toString, hashCode, equals 함수가 재정의 된다는 것인데요. 하나씩 살펴볼까요?
toString 함수
data object Empty
object None
fun main() {
//기존 object 출력
println(None)
// data object 출력
println(Empty)
}
//com.example.myapplication.surface.None@26ba2a48
//Empty
object의 toString 출력은 이름뿐만 아니라 패키지 정보와 메모리 주소가 포함되어 있었습니다. 따라서 기본적으로 데이터의 상태를 간략하게 표현할 수 없습니다. 이를 위해 매번 toString을 override 하는 것은 굉장히 번거로운 작업일 것입니다.
그래서 data object의 toString 함수는 불필요한 정보를 제거하고 오로지 객체의 이름만을 반환합니다.
Equals, Hash Code
eqauls 함수와 hashCode 함수는 data object 들간의 안전한 비교를 위해 재정의되었습니다.
그런데 object는 싱글톤이기 때문에 eqauls와 hashCode의 재정의가 필요한지 의문이 들었는데요. Github Pull Request에서 답을 확인할 수 있었습니다.
Even though data objects are singletons, `equals` and `hashCode` probably should also be generated: * it may be useful to have a stable `hashCode` * as it's in principle possible to create multiple instances of a `data object` class via JVM reflection, and some third-party frameworks may do that, it would make sense to have `equals` implementation that would treat all instances of the same data class as equal.
https://github.com/Kotlin/KEEP/pull/316
그 이유는 유효한 hashCode를 안전하게 반환해야 하며, JVM reflection이나 또 다른 framework로 인해 생성된 여러 인스턴스에 대해 eqauls를 보장해줘야 하기 때문에 재정의가 필요하다고 합니다.
Object 내부 구조
public final class None {
@NotNull
public static final None INSTANCE;
private None() {
}
static {
None var0 = new None();
INSTANCE = var0;
}
}
object의 코드를 decomplie 하면 숨겨진 기본 생성자를 확인할 수 있는데요. private 지정자로 설정되어 있기 때문에 일반적으로 다른 인스턴스를 생성할 수 없지만 JVM reflection이나 또 다른 framework을 통해 객체를 생성할 수 있는 위험은 존재한다고 합니다.
따라서 기존 object의 경우 타입이 같지만 equals는 false로 나올 수 있는 가능성이 있다는 것이죠. hashCode도 동일합니다.
public final class Empty {
@NotNull
public static final Empty INSTANCE;
private Empty() {
}
static {
Empty var0 = new Empty();
INSTANCE = var0;
}
...
public int hashCode() {
return -1772826639;
}
public boolean equals(@Nullable Object var1) {
if (this != var1) {
if (!(var1 instanceof Empty)) {
return false;
}
Empty var2 = (Empty)var1;
}
return true;
}
}
따라서 data object의 경우는 위에서 알아본 위험을 제거하고자 equals 함수를 재정의해서 type 동일하다면 true를 반환하도록 함수 내부 구현이 되어 있는 것을 확인할 수 있습니다.
마치며
data object와 object는 차이점에 대해서 간단하게 알아봤습니다. 개인적으로 toString 함수를 자주 사용하지 않았고, object 비교에 대한 문제점을 실제로 겪어보지 못했기 때문에 크게 와닿지는 않습니다.
하지만 Seald class를 처리할 때 코드의 통일성에 대한 개선은 존재했는데요. data object의 경우 object와 달리 instanceOf 문법을 사용할 수 있어 data class와 object를 다른 방식으로 처리해야 했던 불편함은 사라져서 좋았습니다
'Language > kotlin' 카테고리의 다른 글
[Kotlin] Enum의 새로운 values Function 등장, entries (0) | 2024.05.05 |
---|---|
[Kotlin] Singleton (0) | 2020.06.01 |
[Kotlin] - 기본문법 2 (0) | 2020.02.10 |
Kotlin의 유용한 함수들 - let, apply, run, with (0) | 2020.02.10 |
[Kotlin] Kotlin을 왜 배워야 할까요? (0) | 2020.02.10 |