tgindex
Kotlin | Вопросы собесов

Kotlin | Вопросы собесов

Статистика

Сайт: https://easyoffer.ru/ Все каналы: t.me/+xGeAw6ckJ4liYzQy Контакт для рекламы: @easyoffer_adv

Последний пост
11:05
Последнее чтение
09:59
Постов за неделю
13
Всего постов
30
Тип
открытый
Язык
русский
Категория
Технологии (по похожим)
В каталоге с
13 авг.
Подписчики
2 466
−1 за 5 дн.
Сутки
−2
−0,08%
Неделя
 
Месяц
 
Просмотров на пост
324
28 постов
Вовлечённость
13,1%
к подписчикам
Постов в день
1,9
всего 30
Упоминаний
2
каналов
Охват размещения
оценка
1/24сутки в ленте
243
1/48двое суток
278
1/72трое суток
300

Оценка по просмотрам недавних постов: пост набирает почти всё за первые сутки.

Посты

  • 🤔 Можешь рассказать отличия и в каких случаях их использовать list set map? В Kotlin есть три основных типа коллекций: List — упорядоченный список элементов. Set — множество уникальных элементов. Map — коллекция пар "ключ-значение". 🚩List — упорядоченный список List — это коллекция, в которой можно хранить дубликаты, а элементы доступны по индексу. val numbers = listOf(1, 2, 3, 4, 5) // Immutable (нельзя изменять) val mutableNumbers = mutableListOf(1, 2, 3) // Можно изменять mutableNumbers.add(4) // Добавляем элемент mutableNumbers.removeAt(1) // Удаляем элемент по индексу println(mutableNumbers) // [1, 3, 4] 🚩Set — множество уникальных элементов Set — это коллекция, в которой нет дубликатов. val numbers = setOf(1, 2, 3, 3, 4, 5) // Дубликаты удаляются автоматически println(numbers) // [1, 2, 3, 4, 5] val mutableNumbers = mutableSetOf(1, 2, 3) mutableNumbers.add(3) // Не добавится, потому что уже есть mutableNumbers.add(4) // Добавится println(mutableNumbers) // [1, 2, 3, 4] 🚩Map — коллекция пар "ключ-значение" Map — это структура данных, в которой каждому ключу соответствует одно значение. val userMap = mapOf( 1 to "Alice", 2 to "Bob", 3 to "Charlie" ) // Immutable val mutableUserMap = mutableMapOf(1 to "Alice", 2 to "Bob") mutableUserMap[3] = "Charlie" // Добавляем новый ключ-значение mutableUserMap.remove(1) // Удаляем элемент по ключу println(mutableUserMap) // {2=Bob, 3=Charlie} Ставь 👍 и забирай 📚 Базу знаний

  • 18:102091

    🤔 Что такое Factory Builder? Это паттерн, который комбинирует фабричный подход (создание объектов без указания конкретного класса) и билдер (пошаговая сборка). Позволяет гибко управлять созданием сложных объектов с опциями. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

  • 🤔 Что такое софткод? Софткод (Softcode, Soft Coding) — это подход к программированию, при котором логика программы хранится в конфигурационных файлах, базе данных или других внешних источниках, а не жёстко (hardcoded) прописана в коде. 🚩Разница между Hardcode и Softcode Пример Hardcode (жёстко зашито в коде) val apiUrl = "https://api.example.com" // ❌ Если URL изменится, надо менять код Пример Softcode (гибко через конфигурацию) val apiUrl = Config.get("api_url") // ✅ Загружается из настроек 🚩Где используется софткод? Конфигурационные файлы (config.json, .properties, .xml). База данных (логика, настройки, права пользователей). API и сервер (получение UI-элементов, бизнес-логики с сервера). Скриптовые языки (скрипты загружаются динамически). 🚩Примеры использования Softcode в Android Softcode через SharedPreferences (конфигурация в памяти) val sharedPrefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE) val theme = sharedPrefs.getString("app_theme", "light") // ✅ Загружаем тему из настроек Softcode через remoteConfig (Firebase Remote Config) val minVersion = Firebase.remoteConfig.getInt("min_supported_version") Softcode через JSON-файл (читаем конфиг из assets) fun getConfigValue(context: Context, key: String): String { val json = context.assets.open("config.json").bufferedReader().use { it.readText() } val jsonObject = JSONObject(json) return jsonObject.getString(key) // ✅ Получаем значение из JSON } Ставь 👍 и забирай 📚 Базу знаний

  • 🤔 Когда происходит перегрузка при использовании inline-функций? Перегрузка может произойти при передаче функций с разным числом аргументов, noinline и crossinline, а также при компиляции в Java, где inline-функции превращаются в разные реализации. Коллизии имён могут быть причиной перегрузки. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

  • 🤔 В чем разница между linked list и array list? Являются двумя различными типами коллекций, которые используются для хранения наборов данных. Основные различия между этими двумя структурами данных касаются их внутренней реализации, что влияет на производительность операций добавления, удаления и доступа к элементам. 🚩Внутренняя реализация 🟠ArrayList основан на динамическом массиве. Это позволяет обеспечить быстрый доступ к элементам по индексу, поскольку адрес каждого элемента в памяти может быть вычислен напрямую. Однако, поскольку внутренний массив имеет фиксированный размер, при его переполнении необходимо выделить массив большего размера и скопировать в него все элементы из старого массива, что делает операции добавления и удаления более затратными по времени, особенно для больших объемов данных. 🟠LinkedList основан на двусвязном списке элементов, где каждый элемент (узел) содержит данные и ссылки на предыдущий и следующий элементы в списке. Это обеспечивает высокую производительность операций вставки и удаления, поскольку требуется лишь изменить ссылки у соседних элементов, но доступ к элементам по индексу занимает больше времени, так как для этого нужно последовательно пройти от начала или конца списка до нужного элемента. 🚩Производительность: 🟠ArrayList Быстрый доступ к элементам по индексу. Медленные операции добавления и удаления элементов (особенно в начале и середине списка), так как может потребоваться сдвиг оставшейся части массива. 🟠LinkedList Быстрые операции вставки и удаления элементов, поскольку они требуют только изменения ссылок. Медленный доступ к элементам по индексу, так как для доступа к элементу необходимо пройти по списку. Ставь 👍 и забирай 📚 Базу знаний

  • 🤔 Если профайлер показывает тебе что какой-нибудь фрейм занял 120 миллисекунд, что это значит? Если профайлер показывает, что рендеринг какого-либо фрейма занял 120 миллисекунд, это означает, что этот фрейм выполнялся слишком долго, что приводит к фризам и лагам в пользовательском интерфейсе. 🚩Разбор проблемы 🟠Что значит "фрейм" в этом контексте? В Android интерфейс обновляется 60 раз в секунду (частота 60 FPS). Это значит, что каждый кадр (фрейм) должен рендериться не дольше 16,67 мс (1000 мс / 60 FPS). 🟠Почему 120 мс — это плохо? Если рендеринг кадра занимает 120 мс, то за это время устройство должно было бы нарисовать 7 кадров (120 / 16,67 ≈ 7). Однако оно успело обработать только один, что приводит к заметному подтормаживанию. 🟠Что может вызывать такие задержки? Тяжёлые вычисления в основном потоке (UI Thread) – например, сложные математические операции, работа с JSON, парсинг файлов. Долгие операции с рендерингом – сложные векторные изображения, перегруженные Canvas.draw() или анимации. Синхронные вызовы I/O (чтение файлов, базы данных, сети) – если, например, в onDraw() идёт обращение к диску или базе данных. Неоптимальный layout – глубокая иерархия ViewGroup, частые перерасчёты макетов (measure/layout). 🚩Как исправить? 🟠Перенести тяжёлые вычисления в фоновый поток Coroutines, Executors, WorkManager 🟠Использовать профайлер Android Studio для поиска "узких мест". 🟠Оптимизировать рендеринг избегать сложных onDraw(), использовать ViewStub, RecyclerView. 🟠Пересмотреть макет убрать ненужные ViewGroup, использовать ConstraintLayout. Ставь 👍 и забирай 📚 Базу знаний

  • 🤔 Перечислите маркерные интерфейс? Маркерные интерфейсы не содержат методов, но обозначают поведение объекта. Примеры в Java: - Serializable — объект можно сериализовать. - Cloneable — объект можно клонировать. - Remote — используется для удалённых вызовов. - RandomAccess — для коллекций с быстрым доступом по индексу. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

  • 🤔 Как в Ретрофите в гет методе поставить атрибут в путь в контретом месте? В Retrofit, чтобы передать значение в определенное место URL-адреса для GET-запроса, нужно использовать аннотацию @Path. Эта аннотация позволяет заменить параметр в строке пути на значение, переданное в метод. 🚩Как работает `@Path`? 1. Внутри аннотации @GET вы указываете строку пути, содержащую плейсхолдеры в фигурных скобках ({}). 2. Аннотация @Path связывает переменную метода с плейсхолдером в URL. 3. Когда метод вызывается, значение переменной подставляется вместо плейсхолдера в URL. Допустим, у вас есть API с эндпоинтом https://api.example.com/users/{id}/details Настраиваем интерфейс Retrofit interface ApiService { @GET("users/{id}/details") suspend fun getUserDetails( @Path("id") userId: String ): Response<UserDetails> } Теперь, когда вы вызываете этот метод, вы можете передать значение для id, и Retrofit автоматически подставит его в URL val apiService = retrofit.create(ApiService::class.java) suspend fun fetchUserDetails() { val userId = "123" // Пример значения val response = apiService.getUserDetails(userId) if (response.isSuccessful) { println("User details: ${response.body()}") } else { println("Error: ${response.errorBody()?.string()}") } } 🚩Дополнительные аспекты использования `@Path` 🟠Как работают несколько параметров? Вы можете использовать несколько плейсхолдеров в пути и связать их с несколькими параметрами с помощью @Path. Например: API-эндпоинт https://api.example.com/users/{userId}/posts/{postId} Интерфейс Retrofit interface ApiService { @GET("users/{userId}/posts/{postId}") suspend fun getPostDetails( @Path("userId") userId: String, @Path("postId") postId: String ): Response<PostDetails> } Вызов метода val response = apiService.getPostDetails("123", "456") // URL: https://api.example.com/users/123/posts/456 🟠Что если переменная null или пустая? Если вы передаете null или пустую строку в @Path, это вызовет ошибку, так как Retrofit требует обязательного значения для всех параметров пути. Убедитесь, что передаваемое значение всегда валидно. 🟠Как избежать ошибок при форматировании? Если значение пути может содержать символы, требующие экранирования (например, пробелы, специальные символы), Retrofit автоматически обработает это с помощью кодировки URL. Это делает использование @Path безопасным. @GET("search/{query}") suspend fun search( @Path("query") searchQuery: String ): Response<SearchResults> Если вы вызовете метод с поисковым запросом apiService.search("hello world!") // Retrofit закодирует URL: https://api.example.com/search/hello%20world%21 Ставь 👍 и забирай 📚 Базу знаний

  • 🤔 Нужно запустить синхронный код и получить его результат. Как это будешь делать? Если внутри асинхронного контекста (например, suspend или coroutine), можно использовать: - withContext(Dispatchers.IO) { блок } — синхронно для асинхронного вызова. Если вне корутины — через: - runBlocking { блок } — для запуска корутин синхронно (например, в тестах). - Если обычный код — просто вызвать метод, который возвращает результат. Важно понимать контекст и избегать блокировок в UI. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

  • 🤔 Почему могут пропадать пользовательские данные при повороте экрана? Пропадание пользовательских данных при повороте экрана в Android-приложениях является распространенной проблемой, связанной с тем, как Android управляет жизненным циклом активности. Когда устройство поворачивается, система уничтожает текущую активность и создает её заново, что приводит к потере данных, если они не были сохранены должным образом. 🚩Причины пропадания данных при повороте экрана 🟠Пересоздание активности 🟠Неправильное управление состоянием 🚩Способы предотвращения потери данных Сохранение состояния с помощью onSaveInstanceState и onRestoreInstanceState class MainActivity : AppCompatActivity() { private var userData: String? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) if (savedInstanceState != null) { userData = savedInstanceState.getString("USER_DATA_KEY") // Восстановите данные в пользовательском интерфейсе } } override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putString("USER_DATA_KEY", userData) } override fun onRestoreInstanceState(savedInstanceState: Bundle) { super.onRestoreInstanceState(savedInstanceState) userData = savedInstanceState.getString("USER_DATA_KEY") // Восстановите данные в пользовательском интерфейсе } } Использование Retain Fragment. Этот метод сохраняет данные, используя фрагмент, который сохраняет своё состояние при пересоздании активности. class RetainFragment : Fragment() { var userData: String? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) retainInstance = true } } class MainActivity : AppCompatActivity() { private lateinit var retainFragment: RetainFragment override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val fragmentManager = supportFragmentManager retainFragment = fragmentManager.findFragmentByTag("RETAIN_FRAGMENT") as RetainFragment? ?: RetainFragment().also { fragmentManager.beginTransaction().add(it, "RETAIN_FRAGMENT").commit() } // Используйте данные из RetainFragment val userData = retainFragment.userData } } Использование SavedStateHandle в ViewModel class UserViewModel(savedStateHandle: SavedStateHandle) : ViewModel() { var userData: String? get() = savedStateHandle.get("USER_DATA_KEY") set(value) = savedStateHandle.set("USER_DATA_KEY", value) } class MainActivity : AppCompatActivity() { private lateinit var viewModel: UserViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) viewModel = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get(UserViewModel::class.java) // Используйте данные из ViewModel val userData = viewModel.userData } } Ставь 👍 и забирай 📚 Базу знаний

  • 🤔 Как можно писать RecyclerView, чтобы он кэшировал наперёд? 1. Использовать setItemViewCacheSize для кэширования определённого количества элементов. 2. Включить предзагрузку данных с помощью RecyclerView.OnScrollListener. 3. Реализовать Prefetching через LinearLayoutManager или RecyclerView.LayoutManager. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

  • 🤔 В чем разница между работой с list и работой с sequence? 🚩Основные структуры работы с коллекциями 🟠List Является жадной коллекцией, что означает, что все операции над элементами выполняются немедленно и целиком. Когда вы применяете функции к списку, такие как map, filter и т.д., все элементы проходят через каждую функцию сразу же. В данном примере все элементы списка numbers сначала умножаются на 2, затем фильтруются. Вся работа выполняется сразу для каждого элемента. val numbers = listOf(1, 2, 3, 4, 5) val result = numbers .map { it * 2 } .filter { it > 5 } println(result) // Output: [6, 8, 10] 🟠Sequence Является ленивой коллекцией. Это означает, что элементы обрабатываются по мере необходимости. Функции, применяемые к последовательности, создают цепочку операций, которая выполняется только при обращении к элементам. В этом примере numbers сначала преобразуется в Sequence. Операции map и filter создают цепочку, которая выполняется только при преобразовании обратно в List с помощью toList(). Это позволяет избежать лишних операций и обрабатывать элементы по мере необходимости. val numbers = listOf(1, 2, 3, 4, 5) val result = numbers.asSequence() .map { it * 2 } .filter { it > 5 } .toList() println(result) // Output: [6, 8, 10] 🚩Различия 🟠Жадность против ленивости List: Все элементы обрабатываются сразу при вызове функций. Sequence: Элементы обрабатываются по мере необходимости, что может повысить эффективность. 🟠Производительность List: Подходит для небольших коллекций, где выполнение всех операций сразу не критично. Sequence: Эффективен для больших коллекций или длинных цепочек операций, так как уменьшает количество промежуточных коллекций. 🟠Использование памяти List: Может использовать больше памяти из-за создания промежуточных коллекций. Sequence: Уменьшает использование памяти, обрабатывая элементы по одному. Ставь 👍 и забирай 📚 Базу знаний

  • 🤔 Что такое лямбды с точки зрения синтаксиса в Java и Kotlin? В Java лямбды — это упрощённый синтаксис для анонимных классов, реализующих функциональный интерфейс. Синтаксис: (параметры) -> { тело }. В Kotlin лямбды представляют собой выражения, передаваемые как функции, с синтаксисом { параметры -> тело }. Kotlin более лаконичен, позволяя опускать параметры, если их можно вывести из контекста. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

  • 🤔 Что используешь, если нужно получить элемент или список элементов? В Kotlin есть множество удобных функций для получения одного элемента или списка элементов из коллекций (List, Set, Map). Какую функцию использовать — зависит от задачи. 🚩Получение одного элемента 🟠`get(index)` и `getOrNull(index)` получение по индексу Если индекс может выйти за границы массива, лучше использовать getOrNull(). val list = listOf("A", "B", "C") println(list[1]) // "B" println(list.getOrNull(5)) // null 🟠`first()` и `last()` первый и последний элементы println(list.first()) // "A" println(list.last()) // "C" Используйте firstOrNull() или lastOrNull(), если список может быть пустым println(emptyList<String>().firstOrNull()) // null 🟠`find {}` и `findLast {}` поиск по условию Возвращает первый или последний элемент, удовлетворяющий условию. val numbers = listOf(10, 20, 30, 40) println(numbers.find { it > 15 }) // 20 println(numbers.findLast { it > 15 }) // 40 println(numbers.find { it > 50 }) // null 🟠`single()` и `singleOrNull()` если ожидается только один элемент val oneElementList = listOf(42) println(oneElementList.single()) // 42 println(oneElementList.singleOrNull()) // 42 val emptyList = emptyList<Int>() println(emptyList.singleOrNull()) // null single() бросает исключение, если элементов нет или их больше одного. 🚩Получение нескольких элементов (списка) filter {} – фильтрация элементов по условию val numbers = listOf(1, 2, 3, 4, 5) val evenNumbers = numbers.filter { it % 2 == 0 } println(evenNumbers) // [2, 4] take(n) и takeLast(n) – первые/последние n элементов val items = listOf("a", "b", "c", "d", "e") println(items.take(3)) // [a, b, c] println(items.takeLast(2)) // [d, e] slice(indices) – получение элементов по индексам val sliced = items.slice(listOf(0, 2, 4)) println(sliced) // [a, c, e] map {} – преобразование списка val squared = numbers.map { it * it } println(squared) // [1, 4, 9, 16, 25] Ставь 👍 и забирай 📚 Базу знаний

  • 🤔 В чем заключается передача объекта по ссылке и по значению? – По значению — создаётся копия объекта (в Kotlin: data class, val x = a). – По ссылке — передаётся указатель, и изменения влияют на оригинал. В Java и Kotlin передаются ссылки по значению (сама ссылка копируется, но указывает на один объект). Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

  • 🤔 Чем отличаются data-классы и sealed-классы? data class — класс для хранения данных с автогенерацией equals(), hashCode(), copy(). sealed class — ограниченная иерархия классов, используется для when. 🚩`data class` – для хранения данных data class автоматически создаёт: equals() и hashCode() → сравнение объектов по значениям. copy() → удобное копирование с изменением параметров. toString() → красивый вывод. data class User(val id: Int, val name: String) fun main() { val user1 = User(1, "Alice") val user2 = user1.copy(name = "Bob") // Создаём копию с новым именем println(user1) // User(id=1, name=Alice) println(user2) // User(id=1, name=Bob) } 🚩`sealed class` – для ограниченных иерархий классов sealed class используется, когда есть фиксированное число подклассов. sealed class NetworkState { object Loading : NetworkState() data class Success(val data: String) : NetworkState() data class Error(val message: String) : NetworkState() } fun handleState(state: NetworkState) { when (state) { is NetworkState.Loading -> println("Загрузка...") is NetworkState.Success -> println("Данные: ${state.data}") is NetworkState.Error -> println("Ошибка: ${state.message}") } } 🚩Можно ли использовать `data class` внутри `sealed class`? Да! Это лучший вариант для управления состояниями: sealed class Result { object Loading : Result() data class Success(val data: String) : Result() data class Error(val message: String) : Result() } Ставь 👍 и забирай 📚 Базу знаний

  • 🤔 Расскажи для чего нужен Dagger? Dagger — это библиотека для внедрения зависимостей, упрощающая создание, управление и тестирование объектов. Она генерирует код для автоматического предоставления зависимостей, что делает приложение модульным и устойчивым к изменениям. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

  • 🤔 Почему могут быть проблемы со списками в data class? В data class могут возникнуть проблемы со списками при использовании: Методов copy() – список не копируется, а передаётся по ссылке. Методов equals() и hashCode() – List сравнивается по элементам, что может быть медленно. Mutable списков (MutableList) – изменения внутри списка изменяют все копии объекта. 🚩Проблема `copy()` – список не клонируется data class User(val name: String, val tags: List<String>) fun main() { val original = User("Alice", listOf("Admin", "Editor")) val copy = original.copy() // ✅ Поверхностное копирование println(original.tags === copy.tags) // true (один и тот же объект) } Используем toList(), чтобы создать новый неизменяемый список: fun main() { val original = User("Alice", listOf("Admin", "Editor")) val copy = original.copy(tags = original.tags.toList()) println(original.tags === copy.tags) // false (разные объекты) } 🚩`equals()` и `hashCode()` могут работать медленно data class Message(val id: Int, val content: String, val tags: List<String>) fun main() { val message1 = Message(1, "Привет", listOf("important", "urgent")) val message2 = Message(1, "Привет", listOf("important", "urgent")) println(message1 == message2) // true (сравнивает элементы списка) } Если идентификатор (id) уникален, сравнивать только его data class Message(val id: Int, val content: String, val tags: List<String>) { override fun equals(other: Any?) = other is Message && this.id == other.id override fun hashCode() = id.hashCode() } 🚩`MutableList` в `data class` – неожиданные изменения data class Task(val name: String, val subtasks: MutableList<String>) fun main() { val original = Task("Купить продукты", mutableListOf("Хлеб", "Молоко")) val copy = original.copy() // ✅ Поверхностная копия copy.subtasks.add("Яйца") // ❌ Меняет список в обоих объектах! println(original.subtasks) // [Хлеб, Молоко, Яйца] println(copy.subtasks) // [Хлеб, Молоко, Яйца] } Создаём новый MutableList внутри copy() data class Task(val name: String, val subtasks: List<String>) { fun deepCopy() = Task(name, subtasks.toMutableList()) } fun main() { val original = Task("Купить продукты", mutableListOf("Хлеб", "Молоко")) val copy = original.deepCopy() copy.subtasks.toMutableList().add("Яйца") // ✅ Теперь изменения не влияют на оригинал println(original.subtasks) // [Хлеб, Молоко] println(copy.subtasks) // [Хлеб, Молоко, Яйца] } Ставь 👍 и забирай 📚 Базу знаний

  • 🤔 Что произойдёт, если вместо ключевого слова class использовать object? object в Kotlin создаёт singleton — единственный экземпляр. Нельзя создавать новые экземпляры, он инициализируется при первом обращении. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

  • 🤔 В андроиде существуют мэпы, в которые можно положить примитивные типы? Да! В Android есть специальные Map-коллекции, которые позволяют хранить примитивные типы (int, long, boolean и т. д.) без автоупаковки (autoboxing). 🚩Почему это важно? Обычные HashMap<Int, Int> в Kotlin используют автоупаковку (Integer вместо int), что: Увеличивает потребление памяти (из-за объектов Integer, Long и т. д.). Замедляет работу (из-за ненужного создания объектов). Решение? Использовать специализированные мэпы из android.util! 🚩`SparseArray` (замена `HashMap<Int, Any?>`) Хранит пары Int → Any, но без автоупаковки. import android.util.SparseArray val sparseArray = SparseArray<String>() sparseArray.put(1, "Привет") sparseArray.put(2, "Мир") println(sparseArray[1]) // Привет println(sparseArray[2]) // Мир 🚩`SparseIntArray` (замена `HashMap<Int, Int>`) Хранит пары Int → Int без автоупаковки. import android.util.SparseIntArray val sparseIntArray = SparseIntArray() sparseIntArray.put(1, 100) sparseIntArray.put(2, 200) println(sparseIntArray[1]) // 100 println(sparseIntArray[2]) // 200 🚩`SparseBooleanArray` (замена `HashMap<Int, Boolean>`) Оптимизирован для Int → Boolean пар. import android.util.SparseBooleanArray val sparseBooleanArray = SparseBooleanArray() sparseBooleanArray.put(1, true) sparseBooleanArray.put(2, false) println(sparseBooleanArray[1]) // true println(sparseBooleanArray[2]) // false 🚩`LongSparseArray<T>` (замена `HashMap<Long, T>`) Оптимизирован для Long → Any?, аналог SparseArray, но с Long ключами. import android.util.LongSparseArray val longSparseArray = LongSparseArray<String>() longSparseArray.put(10000000000L, "Длинный ключ") println(longSparseArray[10000000000L]) // Длинный ключ Ставь 👍 и забирай 📚 Базу знаний