Статические методы в Kotlin: как Java-разработчику не потеряться в мире object и companion
Если вы пишете на Java и только начинаете осваивать Kotlin, вы наверняка задавались вопросом: "А где же тут static?". В Java мы привыкли писать public static void main() или MathUtils.max() — это удобно, просто и не требует создания объекта. Но в Kotlin ключевого слова static нет. Вообще. Совсем.
Не паникуйте. Разработчики Kotlin не сошли с ума — они просто решили, что статические методы можно реализовать элегантнее, без глобального состояния и с более чёткой архитектурой. В этой статье мы разберём все способы заменить Java static в Kotlin: от простых функций до уровня пакета до мощного companion object. Вы узнаете, когда что использовать, и увидите живые примеры кода.
Поехали! 🚀
Почему в Kotlin нет static? (и это хорошо)
В Java static — это, по сути, глобальная переменная или метод, привязанный к классу, а не к экземпляру. Это удобно для утилит, но нарушает принципы ООП: статические члены не могут быть переопределены, их сложно тестировать и они создают жёсткие связи.
Kotlin поощряет более чистый подход: функции и свойства могут существовать на уровне пакета (без класса вообще!) или быть организованы в object-синглтоны. А если вам нужно привязать метод к классу (как в Java), используйте companion object. Давайте разберём каждый вариант.
Способ 1: Функции уровня пакета (самый простой)
В Kotlin вы можете объявить функцию или свойство просто в файле, вне класса. Это аналог статического метода в Java, но без лишней обёртки в виде класса-утилиты.
Пример:
// File: MathUtils.kt
package com.example.utils
fun max(a: Int, b: Int): Int {
return if (a > b) a else b
}
val PI = 3.14159 // константа уровня пакета
Теперь эту функцию можно вызывать откуда угодно (после импорта):
import com.example.utils.max
import com.example.utils.PI
fun main() {
println(max(10, 20)) // 20
println(PI) // 3.14159
}
Когда использовать: для простых утилитарных функций и констант, которые не требуют группировки в класс. Это самый лёгкий способ получить "статическое" поведение.
Способ 2: Object-синглтон (для группы связанных функций)
Если вам нужно сгруппировать несколько статических методов вместе (как MathUtils в Java), используйте object. Это синглтон — единственный экземпляр, который создаётся автоматически при первом обращении.
Пример:
object StringUtils {
fun isEmpty(str: String?): Boolean {
return str.isNullOrEmpty()
}
fun capitalizeFirst(str: String): String {
return str.replaceFirstChar { it.uppercase() }
}
const val EMPTY_STRING = ""
}
Использование:
fun main() {
println(StringUtils.isEmpty(null)) // true
println(StringUtils.capitalizeFirst("kotlin")) // Kotlin
println(StringUtils.EMPTY_STRING) // ""
}
Важно: object — это полноценный класс. Он может реализовывать интерфейсы, иметь инициализаторы и даже наследоваться от других классов. Но он не может иметь конструкторов (кроме приватного).
Способ 3: Companion object (для методов, связанных с классом)
Это самый близкий аналог Java static внутри класса. companion object — это объект-компаньон, который живёт внутри класса. Его методы и свойства вызываются через имя класса, как статические.
Пример:
class User(val name: String, val age: Int) {
companion object {
fun createAnonymous(): User {
return User("Anonymous", 0)
}
val MAX_AGE = 150
}
}
// Использование:
fun main() {
val anonymousUser = User.createAnonymous()
println(User.MAX_AGE) // 150
}
Выглядит как static, правда? Но есть нюанс: на самом деле createAnonymous() — это метод объекта-компаньона, а не самого класса. Kotlin просто предоставляет синтаксический сахар для вызова через имя класса.
Как сделать метод "настоящим" static для Java?
Если ваш Kotlin код вызывается из Java, вы можете захотеть, чтобы метод был настоящим статическим (с точки зрения байт-кода). Для этого используйте аннотацию @JvmStatic:
class User(val name: String, val age: Int) {
companion object {
@JvmStatic
fun createAnonymous(): User {
return User("Anonymous", 0)
}
}
}
// Теперь из Java можно вызвать:
// User.createAnonymous(); // работает как статический метод
Без @JvmStatic из Java пришлось бы писать User.Companion.createAnonymous(), что неудобно.
Способ 4: Статические поля (const и @JvmField)
Для констант в Kotlin используйте const val (внутри companion object или на уровне пакета). Это аналог public static final в Java:
class Config {
companion object {
const val APP_NAME = "MyApp"
const val VERSION = "1.0.0"
}
}
// Из Java: Config.APP_NAME
Если вам нужно статическое поле, которое не является константой (например, mutable), используйте @JvmField:
class Counter {
companion object {
@JvmField
var count = 0
}
}
// Из Java: Counter.count++
Когда какой способ выбрать? (шпаргалка)
Давайте подведём итоги в виде простой таблицы решений:
- Одна простая функция без класса → используйте функцию уровня пакета.
- Группа связанных утилит → используйте object (синглтон).
- Методы, логически привязанные к классу (фабрики, константы) → используйте companion object.
- Нужна совместимость с Java → добавьте
@JvmStaticили@JvmField. - Константы →
const val(только примитивы и String).
Типичные ошибки новичков (и как их избежать)
Блоги
Рекомендаций по книгам
Читайте также
Работа с файловой системой в PHP: полное руководство
Мониторинг C++ приложений: метрики и алерты продвинутого уровня
Логирование в PHP приложениях: лучшие практики для начинающих
Expression has changed after it was checked: как победить ошибку в Angular
Асинхронное программирование в TypeScript: полное руководство для начинающих