ProgrammingKotlin開発者

Kotlinにおけるクラス(バリュークラス/インラインクラス)に適用されるキーワード 'inline' はどのように実装されていますか?制限事項は何ですか?これらのクラスはバイトコードのレベルでどのように機能し、いつ、なぜそれらを使用するべきですか?例を挙げて一般的な複雑さを説明してください。

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

回答

Kotlinのインラインクラス(Kotlin 1.5以降は「バリュークラス」という用語)は、コストを最小限に抑えて型のラッパーを作成することを可能にします。コンパイル時に、これらのクラスは内部値(value)に置き換えられ、オブジェクトの生成にかかるオーバーヘッドを回避します。

制限事項と特徴:

  • プライマリコンストラクタには1つのプロパティのみが許可されます。
  • 参照の等価性に対するリンクを保持することはできません(=== は通常通りに機能しません)。
  • バリュークラスは継承可能なクラスではなく、value以外の状態を持つことはできません。
  • すべてのジェネリック型およびプラットフォームAPIは、ボクシングなしでインライン/バリュークラスと動作しない可能性があります。
  • バリュークラスはinitブロックを持たず、value以外のフィールドを持たず、最低限の関数だけを持つことができます。

例:

@JvmInline value class UserId(val value: String) fun getUser(id: UserId) { println("ユーザーID: ${id.value}を読み込んでいます") } val id = UserId("XYZ") getUser(id) // 内部では単にStringとして動作します!

使用するタイミング:

  • 識別子や特別な値に対する型安全性を保証するため。
  • 同様のラッパーを対象としたパフォーマンス改善(オブジェクトが生成されません)。

トリッキーな質問

バリュークラスを継承することや、インターフェース/抽象クラスの階層で使用することはできますか?

回答: いいえ、バリュークラスは他のクラス(インターフェースを除く)を継承できず、継承のために開かれることもできず、initブロックやその他の非静的フィールドを持つことを許可しません。利用可能な唯一のオプションはインターフェースを実装することです。

例:

interface Validatable { fun isValid(): Boolean } @JvmInline value class Email(val raw: String) : Validatable { override fun isValid() = raw.contains("@"); }

テーマの詳細を知らなかったことによる実際のエラーの例


ストーリー

Androidアプリが、Parcelableパラメータにバリュークラスを追加した後、起動時間が急増しました。@Parcelize とバリュークラスの不適切な使用が、シリアル化の各段階でボクシング/アンボクシングを引き起こし、インラインの利点を損なうことが判明しました。


ストーリー

マイクロサービスがUserIdとProductIdの型安全性のためにバリュークラスを積極的に使用し始めましたが、多くの場所でジェネリック関数がリフレクションを必要とし、「ラッパー」とは機能しませんでした。ユニットテストが予期せず失敗し、ClassCastExceptionが発生しました。


ストーリー

Javaから移行されたコードが、最適化のために内部ドメインクラスをバリュークラスに置き換えていましたが、nullableフィールドとしての使用が予想外のヌルポインタ例外を引き起こしました。バリュークラスは外部値もヌルの場合にのみヌルになる可能性があり、古い不変条件を破壊しました。