Как перевести статические методы из Java в Kotlin? (эквивалент static)
Прямой эквивалент: companion object
В Kotlin нет ключевого слова static, но есть companion object (объект-компаньон). Это самый близкий аналог. Объявляется внутри класса, и его члены вызываются через имя класса, как статические методы в Java.
class StringUtils {
companion object {
fun isEmpty(str: String?): Boolean {
return str == null || str.trim().isEmpty()
}
fun capitalize(str: String?): String? {
if (str == null || str.isEmpty()) return str
return str.substring(0, 1).uppercase() + str.substring(1)
}
}
}
// Использование:
if (StringUtils.isEmpty(userInput)) {
println("Input is empty")
}
Но есть важное отличие: companion object — это реальный объект (синглтон). Вы можете дать ему имя, реализовать интерфейсы, наследоваться от классов. Если имя не указано, по умолчанию он называется Companion.
class MyClass {
companion object Named {
fun foo() = "Hello"
}
}
// Вызов:
MyClass.foo() // OK
MyClass.Named.foo() // Тоже OK
Лучший подход для утилитных классов: функции верхнего уровня
Для чистых утилитных функций (как ваш StringUtils) в Kotlin лучше вообще не создавать класс. Просто объявите функции на уровне пакета (вне класса). Это называется функциями верхнего уровня (top-level functions).
// Файл: StringUtils.kt
package com.example.utils
fun isEmpty(str: String?): Boolean {
return str == null || str.trim().isEmpty()
}
fun capitalize(str: String?): String? {
if (str == null || str.isEmpty()) return str
return str.substring(0, 1).uppercase() + str.substring(1)
}
// Использование (после импорта):
import com.example.utils.isEmpty
import com.example.utils.capitalize
if (isEmpty(userInput)) {
println("Input is empty")
}
Это рекомендуемый способ для утилит. Код чище, нет лишнего класса. Из Java эти функции будут видны как статические методы класса StringUtilsKt (по имени файла).
Когда что использовать?
- Функции верхнего уровня — для утилитных функций, констант, вспомогательных методов. Это идиоматичный Kotlin.
- companion object — когда функция логически принадлежит классу (например, фабричный метод
create()), или когда нужно наследование/интерфейсы. - @JvmStatic — если ваш Kotlin-код вызывается из Java и нужно, чтобы метод был именно статическим (а не методом экземпляра
Companion).
class MyClass {
companion object {
@JvmStatic
fun fromJava() { }
}
}
// В Java это будет:
MyClass.fromJava(); // статический метод
Дополнительные фишки Kotlin
- Константы: используйте
const valвнутриcompanion objectили на верхнем уровне. - Расширения: можно добавить "статические" методы к существующим классам через функции-расширения.
- Объекты-одиночки (object declaration): если нужен синглтон с методами, используйте
object MyUtils { ... }.
Итог: для вашего примера с StringUtils лучший выбор — функции верхнего уровня. Это самый идиоматичный и лаконичный способ в Kotlin.
Альтернативный подход: использование object declaration
Если вам нужен не просто набор статических методов, а полноценный объект-синглтон с состоянием (например, кэш или настройки), используйте ключевое слово object:
object StringUtils {
fun isEmpty(str: String?): Boolean = str.isNullOrBlank()
fun capitalize(str: String?): String? = str?.replaceFirstChar { it.uppercase() }
}
// Вызов:
StringUtils.isEmpty("test")
Это создаёт единственный экземпляр класса (синглтон). В отличие от companion object, такой объект не привязан к другому классу — он самостоятельный. Из Java будет виден как StringUtils.INSTANCE.isEmpty(...), если не добавить @JvmStatic.
Когда это удобно?
- Когда нужен mutable state (счётчики, кэш).
- Когда объект реализует интерфейс (например, компаратор).
- Когда вы хотите инкапсулировать логику с состоянием, но не хотите создавать класс с конструктором.
Минус: для простых утилит без состояния это избыточно — лучше использовать функции верхнего уровня.
Выбор между companion object и object зависит от контекста: первый — для методов, логически связанных с классом, второй — для самостоятельных синглтонов.