Kotlinでは、const val修飾子は、トップレベル(ファイルレベル)またはオブジェクト(object)およびコンパニオンオブジェクト内のコンパイル時定数にのみ使用されます。クラス内でvalとして宣言されたプロパティは、通常の最終プロパティになり、静的初期化は行われません。重要な特徴は、const valは継承できないが、valは(許可されている場合)オーバーライド可能です。
定数(const val)は、コンパイル時に値を持つ必要があるため、抽象にすることはできません。通常のvalはオープンプロパティを通じて階層内での定数パターンを実現できますが、ランタイムではゲッターを介してアクセスされるため、Javaでのコンパイルとは異なります。
open class Base { open val info: String = "base" } class Child : Base() { override val info = "child" } object Constants { const val APPLICATION_NAME = "MyApp" }
インターフェースまたは抽象クラスで
const valを宣言し、それをオーバーライド/継承することはできますか?
いいえ。Kotlinでは、インターフェースや抽象クラス内でconst valを宣言することはできません — これはオブジェクト(object)およびトップレベルでのみ許可されます。継承可能なstatic final変数は存在しません。
interface Foo { // const val X = "constant" // コンパイルエラー:const 'val'はトップレベル、オブジェクト、またはコンパニオンオブジェクト内のみ許可されます }
物語
チームは、Androidの複数のモジュールでインターフェースの継承を介して文字列定数を再利用しようとし、それらを
const valとして宣言しましたが — コンパイルエラーが発生し、定数をトップレベルに移動せざるを得ず、カプセル化が悪化しました。
物語
プロジェクトでは、すべてのJavaのstatic finalフィールドをKotlinの
valフィールドに変換し、同様の動作(コンパイル時定数)を期待しましたが、通常のプロパティとゲッターになりました。その結果、アクセス時間が増加し、マイクロサービスアプリケーションのホットパスに悪影響を与えました。
物語
JavaクラスのconstantsコンテナをKotlinに移植する際、開発者はコンパニオンオブジェクト内にconstantsを作成しましたが、Javaコードからのアクセスに問題が発生しました:定数はコンパニオン自体のフィールドとして表示され、クラスのフィールドとしては表示されず、APIでの混乱や追加の相互運用性バグを引き起こしました。