Kotlin 1.9 新機能プレビュー: データ オブジェクト (データ シングルトン)

序文

データ オブジェクト (データ シングルトン) はKotlin 1.9 で導入予定の新機能ですが、1.7.20 からプレビュー可能です。プレビューを開始するには、gradle で KotlinCompileVersion をアップグレードする必要があります。

tasks.withType<KotlinCompile> {
    
    
    kotlinOptions.languageVersion = "1.9"
}

どのような特徴があるのか​​見てみましょう。

toString() の読みやすさの向上

data object通常の と比較してobject、 を呼び出すときtoString()、前者はクラス名を出力し、ハッシュコードを持たなくなり、より読みやすくなります。

object SampleObject
data object SampleDataObject

fun main() {
    
    
    println(SampleObject)     // => SampleObject@58ceff1
    println(SampleDataObject) // => SampleDataObject
}

逆コンパイルされたコードは次のとおりです

public final class SampleDataObject {
    
    
   // ...

   @NotNull
   public String toString() {
    
    
      return "SampleDataObject";
   }
}

equals() は常に true

これは通常、object classシングルトンであるため、==比較したときに返されます。truedata object

object SampleObject
data object SampleDataObject

fun main() {
    
    
    println(SampleObject == SampleObject) // => true
    println(SampleDataObject == SampleDataObject) // => true
}

object class逆コンパイル後は、実際には次のようにコンストラクターのプライベート化を備えたシングルトン モードになります。

//反编译 "object SampleObject"
public final class SampleObject {
    
    
   @NotNull
   public static final SampleObject INSTANCE;

   private SampleObject() {
    
     // private constructor
   }

   static {
    
    
      SampleDataObject var0 = new SampleObject();
      INSTANCE = var0;
   }
}

したがって、リフレクションを通じてコン​​ストラクターを呼び出すことで、さまざまなインスタンスを作成できます object classこのとき==インスタンスが違うため戻ってくる可能性がありますfalse

object SampleObject

fun main() {
    
    
    val newInstance = (SampleObject.javaClass.declaredConstructors[0].apply {
    
    
        isAccessible = true
    } as Constructor<SampleObject>).newInstance()

    println(SampleObject == newInstance) // => false
}

ただしdata object、 の場合は、上記のように呼び出しても が==返されますtrue

data object SampleDataObject

fun main() {
    
    
    val newInstance = (SampleDataObject.javaClass.declaredConstructors[0].apply {
    
    
        isAccessible = true
    } as Constructor<SampleDataObject>).newInstance()

    println(SampleDataObject == newInstance)  // => true
    println(SampleDataObject === newInstance) // => false
}

現時点では、呼び出しのみが===2 つのアドレスを考慮して を返しますfalse
Kotlin のものは==実際には equlas を呼び出しているので、逆コンパイルされた の実装を見てみましょうdata objectequalsこれはinstanceOfによって比較されているため、当然定数であることがわかります。true

public final class SampleDataObject {
    
    
   // ...

   public int hashCode() {
    
    
      return 1802936564;
   }

   public boolean equals(@Nullable Object var1) {
    
    
      if (this != var1) {
    
    
         if (!(var1 instanceof SampleDataObject)) {
    
    
            return false;
         }
      }

      return true;
   }
}

Java の仕様によれば、2 つのインスタンスequlasが等しい場合、hashCode も等しくなければなりませんが、hashCode は定数値なので、当然等しいことがわかります。

シールドの良き相棒

列挙可能な状態を定義するためによく使用されますSealed class/interfaceこの時によく使われるのがobject class以下のようなものです。

sealed class State {
    
    
    object Loading : State()
    data class Success<T>(val response: Response<T>) : State()
    data class Error(val reason: Throwable): State()
}

requestData().subscribe {
    
     state -> 
   println("requestData: $state")  // requestState: State$Loading@34ce8af7
}

Successと はError両方ともデータ クラスであり、最適化後、などの有効な情報がtoString()出力されます。そして、HashCodeなどの無意味なオブジェクト情報を出力します。Success(response= ...)Error(reason=...)Loading

また、出力をより意味のあるものにするために、data objectより適切に調整することができます。Sealed class/interface

sealed class State {
    
    
    data object Loading : State()
    data class Success<T>(val response: Response<T>) : State()
    data class Error(val reason: Throwable): State()
}

val state = State.Loading
println("State: $state") // State: Loading

今後Sealed使用しない場合はdata object、IDE によって警告が表示されます。

データクラスとの違い

data objectdata classと の両方の特性を備えていますobjectただし、data classコンパイル時にメソッドが生成されcopyますcomponentNシングルトンなdata objectのでコンストラクターは一切なく、当然「コピー構築」や「分解」の必要がなく、メソッドcopycomponentNメソッドも生成されません。

おすすめ

転載: blog.csdn.net/vitaviva/article/details/131526602