Programmingバックエンド開発者

Kotlinにおけるインラインクラス(値クラス)とは何か、それらはどのように使用され、どのような制約がありますか?

Hintsage AIアシスタントで面接を突破

答え

問題の経緯

Kotlinでは、原始型や小さな構造体のラッパーを扱う際のランタイムオーバーヘッドを最小化するために、インライン/値クラス(現在は値クラスと呼ばれています)の概念が導入されました。このアイデアは、他の言語(例えば、C#の構造体)から借用されており、型安全性を損なうことなくパフォーマンスを向上させるために有用です。

問題

最適化なしでラッパークラス(例えば、エンティティタイプや識別子のためのラッパー)を作成すると、追加のオブジェクトがメモリに生成され、パフォーマンスやGCに影響を及ぼし、ボクシング/アンボクシングのオーバーヘッドが発生する可能性があります。しばしば、厳密な型付け(例えば、Intの代わりにUserId)が必要だと考えますが、実際にオブジェクトを作成したくありません。

解決策

値クラスは値修飾子を使用して宣言されます。ほとんどの状況では、JVMは追加のオブジェクトを作成せず、値クラスはそのフィールドに直接置換されます(インライン化)。これにより型安全性が提供され、パフォーマンスは「ただのInt」に近いものになります。

コード例:

@JvmInline value class UserId(val value: Int) fun showId(id: UserId) = println(id.value) val id = UserId(15) showId(id) // 別のUserIdオブジェクトを作成せず

主な特徴:

  • クラスはちょうど1つのプロパティ(valまたはvar)を持つ必要がありますが、このタイプはnullableにはできません
  • 継承はサポートされていません(値クラスは継承できず、継承されることもできません)
  • いくつかの制約: initブロックを持つことはできず、lateinitまたは未初期化プロパティを保持することはできず、すべてのケースでリフレクションを使用することはできません

トリック質問

値クラスは複数のプロパティを持つことができますか?

いいえ、値クラスは1つのプロパティしか含むことができません。

// エラー: // value class Money(val amount: Int, val currency: String)

nullableプロパティを持つ値クラスを作成できますか?

値クラスのvalueフィールドはnullableにすることはできません — 非nullableタイプのみです。

// エラー: // value class Name(val value: String?)

値クラスで継承を使用できますか?

値クラスは継承をサポートせず、抽象またはsealedにはできません。

// エラー: // value class NewId(val value: Int): BaseId()

一般的なエラーとアンチパターン

  • 複雑な構造体(例えば、複数のフィールドを持つ)に値クラスを使用しようとすること
  • 値クラスを介してnullable値を保持すること
  • 参照メソッドを使用すること(例えば、メソッドequals/hashCodeはコンパイラバックエンドで予期しない動作をする可能性があります)

実生活の例

ネガティブケース

開発者が2つのプロパティを持つエンティティ用に値クラスを作成し、コンパイルエラーを受けました。

長所:

  • 厳密なタイプを達成しようとしています 短所:
  • 動作しない、コンパイルできない

ポジティブケース

開発者が1つのフィールド(例えば、UserId)の識別子タイプに値クラスを使用し、迅速かつ安全に動作させています。

長所:

  • 簡潔で安全なコード
  • ランタイムオーバーヘッドがない 短所:
  • 非nullable型の1つだけに使用できます