質問の背景:
Kotlinでは、プロパティへのアクセスはゲッターとセッターのメソッドを通じて行われます。パフォーマンスを向上させるために、開発者はアクセサに対してinline修飾子を追加しました。これにより、JVMはコンパイル時に呼び出しコードにget/setの本体を直接挿入することで、呼び出しを最適化できます。
問題:
通常のアクセサメソッドは各プロパティに対して作成されるため、呼び出しのオーバーヘッドが増加します(特に頻繁にアクセスする場合)。時には、開発者はロジックを別のget/setに移動することがありますが、関数呼び出しのオーバーヘッドを避けたいと考えています。
解決策:
ゲッターまたはセッターの実装が短く、重いコードがない場合は、inline修飾子を使用してください。これにより、特にホットパスでオーバーヘッドが減少します。注意点として、インライン化はトップレベルプロパティおよびコンパニオンオブジェクトやオブジェクトオブジェクトのプロパティにのみ機能し、通常のクラス内のプロパティには機能しないことに留意してください。これはJVMの継承の原則によるものです。
コード例:
inline var Int.asHex: String get() = Integer.toHexString(this) set(value) {} inline val String.firstUpperCase: String get() = if (isEmpty()) this else this[0].uppercase() + substring(1)
主な特徴:
通常のクラスプロパティでインラインゲット/セットを使用できますか?
いいえ、ゲッターとセッターのインライン化は、トップレベルまたはオブジェクト(コンパニオンオブジェクトを含む)プロパティにのみ許可され、クラス内のプロパティには許可されていないため、継承の問題を避けることができます。
インラインアクセサでバックフィールド(補助フィールド)にアクセスできますか?
いいえ、インラインアクセサはバックフィールドを持たず、これにアクセスしようとするとコンパイルエラーが発生します。
インラインアクセサが常にバイトコードに影響しますか?
インライン化はコンパイラにコードを組み込む可能性を示すだけです。JITコンパイラは場合によってこれを無視することがあります。さらに、アクセサに重いロジックが含まれていると、得られる効果が反対になることがあります。
プロジェクトで大きなプロパティをインラインとして宣言しましたが、ゲッターで重い変換を処理しているため、ループ内で使用されています。結果として、最終的なバイトコードが膨れ上がり、JITはインライン化をオフにし、パフォーマンスが低下します。
利点:
欠点:
数値を文字列に変換するためにインラインvalを宣言しました。ゲッターはUIコード内で頻繁に呼び出されます。パフォーマンスは高いままで、バイトコードはコンパクトです。
利点:
欠点: