Kotlinのインラインクラス(Kotlin 1.5以降は「バリュークラス」という用語)は、コストを最小限に抑えて型のラッパーを作成することを可能にします。コンパイル時に、これらのクラスは内部値(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フィールドとしての使用が予想外のヌルポインタ例外を引き起こしました。バリュークラスは外部値もヌルの場合にのみヌルになる可能性があり、古い不変条件を破壊しました。