Extension property в Kotlin — что это, синтаксис и применение

Автор: IT Sectr Опубликовано: 2026-06-21 Время чтения: 8 мин

extension property — механизм Kotlin, позволяющий добавлять новые свойства к существующим классам без наследования и без изменения исходного кода. В отличие от extension functions, properties-расширения не могут хранить состояние — они объявляются только с геттером и, опционально, сеттером, поскольку не имеют backing field. По данным Kotlin Documentation, 2025, extension properties компилируются в статические методы getter и setter с receiver в качестве первого параметра.

Главное

  • Extension property — свойство с receiver type, доступное через синтаксис свойств Kotlin
  • Нет backing field — extension property не может хранить состояние, только вычислять
  • Геттер обязателен, сеттер опционален — объявляются как обычные extension функции
  • Nullable-типы поддерживаются: receiver может быть nullable с проверкой внутри
  • Mutable extension property — только при объявлении var с геттером и сеттером

Что такое extension property в Kotlin?

extension property — это синтаксическая конструкция Kotlin, которая добавляет свойство к существующему типу без изменения его объявления. Свойство объявляется с указанием receiver-типа и обязательно содержит геттер. Ключевое отличие от обычных свойств — отсутствие 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), overhead отсутствует полностью.

Используйте extension properties для коротких вычисляемых значений, которые должны выглядеть как свойства, а не как вызовы методов — это улучшает читаемость кода и соблюдает принцип единообразного доступа.

Синтаксис extension property: val и var

Для объявления extension property используется синтаксис, похожий на обычное свойство, но с префиксом receiver-типа. val объявляет read-only extension property с обязательным геттером, var — mutable с геттером и опциональным сеттером.

kotlin
// Read-only extension property
val String.isEmail: Boolean
    get() = this.contains("@") && this.contains(".")

// Call
val valid = "test@test.com".isEmail

Обратите внимание: extension property вызывается без скобок — str.isEmail, а не str.isEmail(). Это и есть ключевое различие между extension property и extension function: property выглядит как поле, хотя на самом деле вычисляется через геттер.

Generic extension property

Extension properties могут быть обобщёнными — receiver может использовать generic-параметры. Это позволяет создавать универсальные свойства, работающие с любым типом коллекции.

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, возвращая второй элемент списка или null, если элементов меньше двух. Это типичный пример, где extension property уместнее функции — обращение выглядит как чтение поля.

Почему extension property не может хранить состояние

Extension property не может иметь backing field, потому что она не добавляется в метаданные класса — она существует только как пара статических функций getter/setter. Backing field (ключевое слово field в Kotlin) — это внутреннее поле класса, которое хранит значение свойства. У extension property нет доступа к внутренней структуре класса.

kotlin
// ❌ ERROR: extension property cannot have a backing field
var String.cachedValue: String
    get() = "computed"
    set(value) {
        field = value // field is not accessible!
    }

// ✅ CORRECT: use external storage
val cache = MutableMap<String, String>()

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

Внешний Map в примере решает проблему хранения, но порождает другую — утечку памяти. Полученные через extension property значения живут в Map вечно, если их не очищать. Это ограничение делает extension property неподходящими для кэширования или хранения временных данных.

Для кэширования рекомендуется использовать WeakHashMap или механизмы с автоматической очисткой. JetBrains рекомендует избегать использования var extension properties с внешним хранилищем в production-коде без тщательного управления жизненным циклом.

Extension property vs extension function: когда что выбирать

Выбор между extension property и extension function зависит от семантики: свойство описывает характеристику объекта, а функция — действие. Принцип единообразного доступа (Uniform Access Principle) гласит: клиент не должен знать, вычисляется значение или хранится. Если значение можно представить как характеристику (длину, размер, статус) — используйте property.

Критерий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 для операций с побочными эффектами.

Mutable extension property с var и сеттером

Extension property с ключевым словом var поддерживает сеттер, но без возможности хранить значение — сеттер обычно выполняет побочное действие или сохраняет данные во внешнем хранилище. Синтаксис аналогичен mutable свойствам классов.

kotlin
// Mutable extension property with setter
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. Геттер возвращает последний символ StringBuilder, сеттер заменяет его на новое значение. Обратите внимание: состояние хранится в самом StringBuilder (через setCharAt), а не в отдельном поле — это корректное использование extension property.

Практические примеры extension properties

В реальных проектах extension properties чаще всего применяются для упрощения доступа к данным коллекций, для расчёта размеров или статусов UI-элементов, и для создания удобного API поверх существующих классов. Стандартная библиотека Kotlin активно использует этот механизм: size, indices, lastIndex для коллекций — это extension properties.

kotlin
// Extension properties for collections
val List<Int>.sumFast: Int
    get() = fold(0) { acc, i -> acc + i }

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

// Extension property for Android View
val View.isVisible: Boolean
    get() = visibility == View.VISIBLE

// Null check via safe receiver
val String?.isNullOrBlank: Boolean
    get() = this == null || this.isBlank()

Extension property isVisible для View — пример, который стоит знать каждому Android-разработчику. Вместо view.visibility == View.VISIBLE можно писать view.isVisible. Это не только короче, но и читается как естественный язык: «если view видим». Несмотря на простоту, такие свойства существенно улучшают читаемость кода.

Часто задаваемые вопросы

Можно ли объявить extension property для companion object?

Нет, extension properties не могут быть объявлены для companion object или object declaration. Механизм extension применим только к классам, интерфейсам и nullable-типам. Для object используйте обычные функции верхнего уровня.

Чем extension property отличается от inline-свойства?

Inline-свойство (с модификатором inline) — механизм Kotlin для вызова геттера/сеттера без создания объекта-свойства. Extension property всегда компилируется в статический метод, а inline-свойство — в вызов без обёртки. Они решают разные задачи: extension property добавляет свойство к существующему типу, inline — оптимизирует вызовы своих свойств.

Поддерживают ли extension property аннотации?

Да, extension property может содержать аннотации, но только на уровне объявления. Нельзя аннотировать отдельно getter или setter extension property — в отличие от обычных свойств класса. Пример: @JvmName("getIsValid") val String.isValid get() = true.

Можно ли использовать extension property с companion object класса?

Нет, extension properties нельзя объявить с companion object в качестве receiver. Это ограничение языка — extension property работает только с экземплярами типов, а companion object — статический контекст. Используйте extension функции верхнего уровня или константы.

Влияет ли extension property на размер APK?

Минимально. Каждое extension property добавляет один статический метод getter (и опционально setter) в скомпилированный байт-код. Для сравнения: создание класса-обёртки с таким же свойством добавляет целый класс. Extension properties — более лёгкий подход к расширению функциональности.

Итоги

  • Extension property — вычисляемое свойство для существующего типа без наследования
  • Нет backing field — состояние не хранится, только вычисляется через getter
  • var с сеттером — возможен, но требует внешнего хранилища для записи данных
  • Синтаксис — val/var с receiver-типом и обязательным getter
  • Производительность — нулевой overhead, компилируется в статический метод
  • Применение — вычисляемые характеристики: длина, статус, размер, проверки
  • Ограничение — не подходит для хранения состояния, кэширования без управления памятью

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также