Эквивалент static final полей из Java в Kotlin: как объявить константы?
Эквивалент Java static final в Kotlin: const val и companion object
В Kotlin нет точного синтаксического аналога static final, но есть несколько способов добиться того же поведения. Всё зависит от того, нужна ли вам константа времени компиляции (как в Java с static final) или просто неизменяемое значение, которое вычисляется во время выполнения.
1. Константы времени компиляции: const val (рекомендуемый способ)
Если ваше значение известно на этапе компиляции (примитивные типы или строки), используйте const val на верхнем уровне (вне класса) или внутри companion object с аннотацией @JvmStatic. Это самый близкий аналог public static final в Java.
// Верхнеуровневая константа (аналог package-private static final)
const val MAX_SIZE = 100
class Constants {
companion object {
// Аналог public static final
@JvmStatic
const val APP_NAME = "MyApp"
// Аналог private static final
private const val INTERNAL_KEY = "secret"
}
}
Ключевое отличие от Java: const val работает только с примитивами (Int, Long, Double и т.д.) и строками. Для объектов, списков или других сложных типов используйте val без const.
2. Неизменяемые поля без времени компиляции: val
Если вам нужно поле, которое инициализируется один раз, но не является константой времени компиляции (например, результат вызова функции), используйте val внутри companion object. Оно будет создано при загрузке класса.
class Config {
companion object {
val MAX_USERS: Int = calculateMaxUsers() // вычисляется во время выполнения
val DEFAULT_TIMEOUT: Long = TimeUnit.SECONDS.toMillis(30)
}
}
В Java этот код будет скомпилирован как static final, но без оптимизации встраивания констант.
3. Аннотация @JvmStatic: когда она нужна?
Если вы пишете код на Kotlin, но вызываете его из Java, используйте @JvmStatic. Без неё доступ к полю будет через Constants.Companion.getAPP_NAME(), а с ней — как Constants.APP_NAME.
4. Разница между const val и val в companion object
- const val: встраивается в место использования на этапе компиляции (как Java
static finalс примитивами/строками). Нельзя использовать для объектов или вычисляемых значений. - val: создаётся как обычное статическое поле, инициализируется при загрузке класса. Может хранить любые объекты.
5. Полный пример: смешанный подход
// Верхнеуровневая константа
const val API_VERSION = "v2.1"
class NetworkConfig {
companion object {
@JvmStatic
const val BASE_URL = "https://api.example.com"
@JvmStatic
val TIMEOUT_DURATION: Long = TimeUnit.SECONDS.toMillis(30)
// Для сложных объектов используем lazy
val DEFAULT_HEADERS: Map<String, String> by lazy {
mapOf("Authorization" to "Bearer token")
}
}
}
В Java вы сможете обращаться: NetworkConfig.BASE_URL, NetworkConfig.TIMEOUT_DURATION.
Итоговая таблица соответствия
- Java:
public static final int MAX = 10;→ Kotlin:const val MAX = 10(на верхнем уровне) или@JvmStatic const val MAX = 10внутри companion object. - Java:
public static final List<String> NAMES = List.of("a");→ Kotlin:@JvmStatic val NAMES = listOf("a")внутри companion object.
Используйте const val для простых неизменяемых значений, известных на этапе компиляции. Для всего остального — val с @JvmStatic при необходимости.
Альтернативный подход: объект-одиночка (object) вместо класса с companion object
Если вам не нужен класс с несколькими константами, а только группа констант, можно использовать объявление object. Это создаст синглтон, эквивалентный статическому классу-утилите в Java.
object AppConstants {
const val MAX_LOGIN_ATTEMPTS = 5
val DEFAULT_AVATAR_URL = "https://example.com/avatar.png"
}
Доступ в Kotlin: AppConstants.MAX_LOGIN_ATTEMPTS. В Java: AppConstants.INSTANCE.getMAX_LOGIN_ATTEMPTS() (без @JvmStatic) или AppConstants.MAX_LOGIN_ATTEMPTS (с @JvmStatic).
Когда использовать object вместо companion object?
- Когда константы логически не принадлежат конкретному классу.
- Когда вы хотите избежать лишней вложенности (companion object внутри класса).
- Когда нужно импортировать константы:
import com.example.AppConstants.MAX_LOGIN_ATTEMPTS.
Недостаток: в Java придётся писать AppConstants.INSTANCE, если не добавить @JvmField или @JvmStatic. Для максимальной совместимости с Java используйте @JvmField для простых полей:
object AppConstants {
@JvmField
val TIMEOUT = 5000L
}
Тогда в Java будет AppConstants.TIMEOUT напрямую.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги