Что такое аннотация @JvmStatic и когда она нужна?
Аннотация @JvmStatic в Kotlin используется для улучшения совместимости Kotlin-кода с Java. Она сообщает компилятору Kotlin, что определённую функцию или свойство в object или companion object нужно сгенерировать как статический метод/поле в байткоде JVM. Это позволяет Java-коду обращаться к этим членам так, как если бы они были обычными static методами/полями в Java.
Где можно использовать @JvmStatic
Аннотацию @JvmStatic можно применять:
-
Внутри object (singleton-объекты).
-
Внутри companion object (статические секции классов).
-
Для функций.
-
Для свойств (только val и var с @JvmField, либо с get/set).
Поведение по умолчанию без @JvmStatic
В Kotlin любой метод, объявленный в object или companion object, на уровне JVM по умолчанию не является static, а реализуется как обычный метод экземпляра вложенного объекта:
class Utils {
companion object {
fun sayHello() = println("Hello")
}
}
Java не может вызвать этот метод напрямую как Utils.sayHello().
Java-код будет выглядеть так:
Utils.Companion.sayHello();
Что делает @JvmStatic
Если к той же функции добавить @JvmStatic, Kotlin создаёт два метода:
-
Один как static, доступный напрямую из Java.
-
Второй — обычный метод, как и раньше (для вызова из Kotlin).
class Utils {
companion object {
@JvmStatic
fun sayHello() = println("Hello")
}
}
Теперь Java может вызвать:
Utils.sayHello(); // ✅ статический вызов
Utils.Companion.sayHello(); // ✅ обычный вызов через объект
То же касается object:
object Logger {
@JvmStatic
fun log(msg: String) { println(msg) }
}
Java:
Logger.log("Hello"); // ✅
Logger.INSTANCE.log("Hello"); // тоже возможно, как без аннотации
Применение к свойствам
Можно использовать @JvmStatic с геттерами и сеттерами:
object Settings {
@JvmStatic
val version: String = "1.0"
}
Java:
String v = Settings.getVersion();
Чтобы получить прямой доступ к полю без геттера, используют @JvmField, а не @JvmStatic:
object Settings {
@JvmField
val version: String = "1.0"
}
Java:
String v = Settings.version;
Зачем вообще нужна @JvmStatic
Kotlin ориентирован на использование object и companion object, но в Java такой модели нет. Там есть только static. Когда Kotlin-код должен быть использован из Java (например, в Android, библиотеке или миграции), приходится адаптировать его интерфейс под Java-реалии.
Без @JvmStatic, вызов Java → Kotlin требует обращения к Companion, что непривычно и может быть неудобно.
Особенности компиляции
Когда вы используете @JvmStatic, компилятор Kotlin:
-
Генерирует дополнительный static-метод в том классе, где вы это указали.
-
Не удаляет старый метод — он остаётся для вызова из Kotlin.
-
Позволяет использовать оба подхода вызова в Java — и через Companion, и напрямую как static.
Пример полного класса
class MyMath {
companion object {
fun square(x: Int): Int = x \* x
@JvmStatic
fun cube(x: Int): Int = x \* x \* x
}
}
Java:
int a = MyMath.Companion.square(5); // через Companion
int b = MyMath.cube(5); // напрямую как static
Когда использовать @JvmStatic
-
Если ваш Kotlin-код будет использоваться из Java.
Это актуально в Android, библиотеках общего назначения или при миграции Java-проектов на Kotlin. -
Если вы хотите улучшить читаемость и привычность интерфейса для Java-разработчиков.
Вместо ClassName.Companion.method() они смогут использовать ClassName.method(). -
Когда используете Kotlin-объекты в Java-коде Android.
Например, вызовы из Activity, Fragment, BroadcastReceiver и других Java-классов.
Когда не надо использовать @JvmStatic
-
Если вы пишете код исключительно на Kotlin и не планируете Java-интеграции.
-
Если не требуется обращаться к этим методам как к static в Java.
-
Если используете Kotlin Multiplatform — @JvmStatic специфична только для JVM.