KotlinのExtension property — その概要、構文、使用法

著者: IT Sectr 公開日: 2026-06-21 読了時間: 8 分

extension property — 継承なしで、ソースコードを変更せずに既存のクラスに新しいプロパティを追加できるKotlinのメカニズムです。extension functionsとは異なり、extension propertiesは状態を保持できません — backing fieldを持たないため、getterのみ、またはオプションでsetterとともに宣言されます。Kotlin Documentation, 2025によると、extension propertiesはreceiverを最初のパラメータとする静的getterおよびsetterメソッドにコンパイルされます。

主要ポイント

  • Extension property — receiver typeを持つプロパティで、Kotlinのプロパティ構文を通じてアクセス可能
  • backing fieldなし — extension propertyは状態を保持できず、計算のみ可能
  • Getterは必須、setterはオプション — 通常のextension functionsと同様に宣言
  • Null許容型をサポート:receiverは内部チェック付きでnullableにできる
  • 可変extension property — getterとsetterを持つvarとして宣言した場合のみ

Kotlinのextension propertyとは?

Extension propertyは、宣言を変更せずに既存の型にプロパティを追加するKotlinの構文構造です。プロパティはreceiver typeで宣言され、getterを含む必要があります。通常のプロパティとの主な違いはbacking fieldがないことです:extension propertyはデータを保存できず、receiverオブジェクトに基づいて計算のみ行います。

Kotlin Foundation Survey (2024)によると、extension propertiesはextension functionsよりも人気が低く、約45%の開発者が定期的に使用しています。これは状態を持てないという制限によるもので、適用範囲を狭めています。それでも、型に論理的に結びついた計算プロパティには、extension propertiesが最も簡潔な選択肢です。

Extension propertiesは、静的getterとsetterメソッドのペアにコンパイルされます。バイトコードレベルでは、extension propertyの呼び出しとextension functionの呼び出しに違いはありません — どちらもreceiverパラメータを持つ静的メソッドになります。JetBrains(Kotlin Docs, 2025)によると、オーバーヘッドはまったくありません。

メソッド呼び出しではなくプロパティのように見せたい短い計算値にはextension propertiesを使用してください — これによりコードの可読性が向上し、Uniform Access Principleに従います。

Extension propertyの構文:valとvar

Extension propertyを宣言するには、通常のプロパティと同様の構文を使用しますが、receiver typeのプレフィックスを付けます。valは必須のgetterを持つ読み取り専用extension propertyを宣言し、varはgetterとオプションのsetterを持つ可変のものを宣言します。

kotlin
// 読み取り専用extension property
val String.isEmail: Boolean
    get() = this.contains("@") && this.contains(".")

// 呼び出し
val valid = "test@test.com".isEmail

注意:extension propertyは括弧なしで呼び出されます — str.isEmailであり、str.isEmail()ではありません。これがextension propertyとextension functionの主な違いです:プロパティはフィールドのように見えますが、実際にはgetterを通じて計算されます。

ジェネリックextension property

Extension propertiesはジェネリックにすることができます — receiverはジェネリック型パラメータを使用できます。これにより、任意のコレクション型で動作する汎用プロパティを作成できます。

kotlin
val List<T>.secondOrNull: T?
    get() = if (size >= 2) this[1] else null

val items = listOf("a", "b", "c")
val second = items.secondOrNull // "b"

secondOrNullプロパティは任意の型Tで機能し、リストの2番目の要素を返すか、要素が2つ未満の場合はnullを返します。これはextension propertyが関数よりも適切な典型的な例です — アクセスがフィールドの読み取りのように見えます。

Extension propertyが状態を保持できない理由

Extension propertyはクラスのメタデータに追加されないため、backing fieldを持つことができません — 静的getter/setter関数のペアとしてのみ存在します。Backing field(Kotlinのfieldキーワード)は、プロパティ値を格納するクラスの内部フィールドです。Extension propertyはクラスの内部構造にアクセスできません。

kotlin
// ❌ エラー:extension propertyはbacking fieldを持てません
var String.cachedValue: String
    get() = "computed"
    set(value) {
        field = value // フィールドにアクセスできません!
    }

// ✅ 正解:外部ストレージを使用してください
val cache = MutableMap<String, String>()

var String.cachedValue: String
    get() = cache[this] ?: ""
    set(value) { cache[this] = value }

例の外部Mapは保存の問題を解決しますが、別の問題 — メモリリークを引き起こします。Extension propertyを通じて取得した値は、クリーンアップしない限りMapに永久に残ります。この制限により、extension propertiesはキャッシュや一時データの保存に適さなくなります。

キャッシュには、WeakHashMapまたは自動クリーンアップメカニズムの使用が推奨されます。JetBrainsは、ライフサイクル管理を慎重に行わずに、プロダクションコードで外部ストレージを持つvar extension propertiesを使用しないことを推奨しています。

Extension property vs extension function:どちらを選ぶべきか

Extension propertyとextension functionの選択はセマンティクスに依存します:プロパティはオブジェクトの特性を記述し、関数はアクションを記述します。Uniform Access Principleは次のように述べています:クライアントは値が計算されるか保存されるかを知るべきではありません。値を特性(長さ、サイズ、ステータス)として表現できる場合は、プロパティを使用してください。

基準Extension propertyExtension function
呼び出し括弧なし:obj.property括弧あり:obj.function()
セマンティクス特性、属性アクション、操作
Backing field非対応該当なし
パラメータgetter/setterのみ任意のパラメータ
パフォーマンス同じ(静的メソッド)同じ(静的メソッド)
text.lengthtext.isEmail()

ルールは簡単です:操作がパラメータを取る場合はextension functionを使用します。パラメータなしの単純な計算値の場合はextension propertyを使用します。Android Architecture Guide(Google, 2025)によると、データアクセスにはextension propertiesを、副作用のある操作にはextension functionsを優先する必要があります。

varとsetterを持つ可変extension property

varキーワードを持つextension propertyはsetterをサポートしますが、値を保存する機能はありません — setterは通常、副作用を実行するか、外部ストレージにデータを保存します。構文は可変クラスプロパティと同様です。

kotlin
// setter付き可変extension property
var StringBuilder.lastChar: Char
    get() = this[length - 1]
    set(value) {
        this.setCharAt(length - 1, value)
    }

val sb = StringBuilder("Kotlin")
println(sb.lastChar) // n
sb.lastChar = '!'
println(sb) // Kotli!

lastCharプロパティはKotlinドキュメントの古典的な例です。GetterはStringBuilderの最後の文字を返し、setterはそれを新しい値に置き換えます。注意:状態は個別のフィールドではなく、StringBuilder自体(setCharAt経由)に保存されます — これはextension propertyの正しい使用法です。

Extension propertiesの実践例

実際のプロジェクトでは、extension propertiesは主にコレクションデータへのアクセスを簡素化したり、UI要素のサイズやステータスを計算したり、既存のクラス上に便利なAPIを作成したりするために使用されます。Kotlin標準ライブラリはこのメカニズムを積極的に使用しています:コレクションのsize、indices、lastIndexはextension propertiesです。

kotlin
// コレクション用extension properties
val List<Int>.sumFast: Int
    get() = fold(0) { acc, i -> acc + i }

val String.half: String
    get() = this.substring(0, length / 2)

// Android View用extension property
val View.isVisible: Boolean
    get() = visibility == View.VISIBLE

// 安全なreceiverによるnullチェック
val String?.isNullOrBlank: Boolean
    get() = this == null || this.isBlank()

Viewのextension property isVisibleは、すべてのAndroid開発者が知っておくべき例です。view.visibility == View.VISIBLEの代わりに、view.isVisibleと書くことができます。これは短いだけでなく、自然言語のように読めます:「ビューが表示されている場合」。シンプルさにもかかわらず、このようなプロパティはコードの可読性を大幅に向上させます。

よくある質問

companion objectに対してextension propertyを宣言できますか?

いいえ、extension propertiesはcompanion objectやobject declarationに対して宣言できません。拡張メカニズムはクラス、インターフェース、null許容型にのみ適用されます。objectには、通常のトップレベル関数を使用してください。

Extension propertyとinlineプロパティの違いは何ですか?

Inlineプロパティ(inline修飾子付き)は、プロパティオブジェクトを作成せずにgetter/setterを呼び出すKotlinのメカニズムです。Extension propertyは常に静的メソッドにコンパイルされ、inlineプロパティはラッパーなしの呼び出しにコンパイルされます。これらは異なる問題を解決します:extension propertyは既存の型にプロパティを追加し、inlineは自身のプロパティの呼び出しを最適化します。

Extension propertiesはアノテーションをサポートしていますか?

はい、extension propertyはアノテーションを持つことができますが、宣言レベルでのみです。通常のクラスプロパティとは異なり、extension propertyのgetterまたはsetterを個別にアノテーションすることはできません。例:@JvmName("getIsValid") val String.isValid get() = true.

クラスのcompanion objectでextension propertyを使用できますか?

いいえ、extension propertiesはcompanion objectをreceiverとして宣言できません。これは言語の制限です — extension propertyは型のインスタンスでのみ機能し、companion objectは静的コンテキストです。トップレベルのextension関数または定数を使用してください。

Extension propertyはAPKサイズに影響しますか?

最小限です。各extension propertyは、コンパイルされたバイトコードに1つの静的getterメソッド(およびオプションでsetter)を追加します。比較すると、同じプロパティを持つラッパークラスを作成すると、クラス全体が追加されます。Extension propertiesは機能を拡張するためのより軽量なアプローチです。

まとめ

  • Extension property — 継承なしで既存の型に追加する計算プロパティ
  • backing fieldなし — 状態は保存されず、getterを通じてのみ計算される
  • setter付きvar — 可能だが、データ書き込みには外部ストレージが必要
  • 構文 — receiver typeと必須のgetterを持つval/var
  • パフォーマンス — ゼロオーバーヘッド、静的メソッドにコンパイル
  • 用途 — 計算特性:長さ、ステータス、サイズ、チェック
  • 制限 — 状態の保存、メモリ管理なしのキャッシュには不向き

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください