Kotlin | Вопросы собесов
2.56K subscribers
28 photos
972 links
Download Telegram
🤔 Вставка значения быстрее в Linked list или в Array list?

🚩Вставка в `ArrayList`

ArrayList реализован на основе массива.

🟠Вставка в конец
Амортизированное O(1). Если массив не заполнен, элемент добавляется в конец списка. В случае, если массив заполнен, требуется выделение нового массива и копирование элементов, что занимает O(n) времени.
val arrayList = ArrayList<Int>()
arrayList.add(1) // Быстрая вставка в конец


🟠Вставка в начало или середину
O(n). Необходимо сдвинуть все элементы, начиная с позиции вставки, чтобы освободить место для нового элемента. Это требует времени, пропорционального количеству элементов после позиции вставки.
arrayList.add(0, 2) // Медленная вставка в начало
arrayList.add(1, 3) // Медленная вставка в середину


🚩Вставка в LinkedList

LinkedList реализован на основе узлов, где каждый узел содержит ссылку на следующий и/или предыдущий узел (в случае двусвязного списка).

🟠Вставка в начало: O(1). Для добавления элемента в начало достаточно изменить ссылки первого узла и нового узла.
val linkedList = LinkedList<Int>()
linkedList.addFirst(1) // Быстрая вставка в начало


🟠Вставка в конец
O(1) (если есть ссылка на последний узел) или O(n) (если необходимо пройти весь список). Если список двусвязный и хранится ссылка на последний элемент, вставка в конец осуществляется за O(1). В противном случае, требуется пройти весь список до конца.
linkedList.addLast(2) // Быстрая вставка в конец, если есть ссылка на последний узел


🟠Вставка в середину
O(n). Необходимо пройти список до нужной позиции и изменить ссылки узлов.
linkedList.add(1, 3) // Медленная вставка в середину


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
🤔 Чем отличаются inner классы от nested?

Nested class — статический, не имеет доступа к экземпляру внешнего класса.
Inner class — нестатический, может обращаться к полям и методам внешнего класса, включая приватные.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6
🤔 Как LeakCanary находит ссылку на уничтоженную Activity?

Использует комбинацию слабых ссылок (WeakReference), анализ кучи и цепочек удержания, чтобы найти ссылки на уничтоженные Activity или другие объекты, которые должны были быть освобождены сборщиком мусора. Вот более подробное объяснение того, как это работает:

🚩Шаги

1⃣Создание слабой ссылки (WeakReference)
Когда Activity (или другой компонент) уничтожается, LeakCanary создает слабую ссылку на этот объект.
val weakReference = WeakReference(activity)


2⃣Ожидание сборки мусора (Garbage Collection)
LeakCanary инициирует сборку мусора, чтобы попытаться освободить уничтоженный объект.
System.gc()
System.runFinalization()


3⃣Проверка слабой ссылки
LeakCanary проверяет, освобождена ли слабая ссылка. Если объект не был освобожден, это указывает на возможную утечку памяти.
if (weakReference.get() != null) {
// Объект все еще удерживается в памяти, вероятна утечка
}


4⃣Снимок кучи (Heap Dump)
Если слабая ссылка не была освобождена, LeakCanary создает снимок кучи (heap dump) для дальнейшего анализа.
val heapDumpFile = createHeapDump()


5⃣Анализ кучи с помощью Shark
LeakCanary использует библиотеку Shark для анализа снимка кучи. Shark проверяет все объекты в куче и их удерживающие ссылки.
val heapAnalyzer = HeapAnalyzer()
val analysis = heapAnalyzer.analyze(heapDumpFile)


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥1
🤔 Что произойдёт, если вместо ключевого слова class использовать object?

object в Kotlin создаёт singleton — единственный экземпляр. Нельзя создавать новые экземпляры, он инициализируется при первом обращении.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
🤔 Что происходит когда делаешь ==?

В Kotlin оператор == используется для структурного сравнения объектов.

🚩Что делает `==` в Kotlin?

Оператор == вызывает метод equals(), чтобы проверить содержимое объектов, а не их ссылки.
data class User(val name: String)

fun main() {
val user1 = User("Alice")
val user2 = User("Alice")

println(user1 == user2) // true (структурное сравнение)
println(user1 === user2) // false (сравнение ссылок)
}


🚩Чем `==` отличается от `===`?

== проверяет, равны ли данные объектов (equals()).
=== проверяет, ссылаются ли объекты на один и тот же участок памяти.
val str1 = "Hello"
val str2 = "Hello"
println(str1 == str2) // true (содержимое одинаковое)
println(str1 === str2) // true (Kotlin кеширует строки)

val obj1 = String("Hello".toCharArray())
val obj2 = String("Hello".toCharArray())
println(obj1 == obj2) // true (содержимое одинаковое)
println(obj1 === obj2) // false (разные объекты в памяти)


🚩Как работает `==` для классов?

Если equals() не переопределён, то сравниваются ссылки (как ===).
class Person(val name: String)

fun main() {
val p1 = Person("Bob")
val p2 = Person("Bob")

println(p1 == p2) // false (equals() не переопределён, сравниваются ссылки)
}


Чтобы == работал по содержимому, нужно переопределить equals()
class Person(val name: String) {
override fun equals(other: Any?): Boolean {
return other is Person && other.name == this.name
}
}

fun main() {
val p1 = Person("Bob")
val p2 = Person("Bob")

println(p1 == p2) // true (equals() сравнивает содержимое)
}


🚩Как `==` работает с `null`?

Kotlin предотвращает NullPointerException при сравнении с null:
val a: String? = null
val b: String? = "Hello"

println(a == b) // false (без NPE)
println(a == null) // true


Когда a == b, на самом деле выполняется:
a?.equals(b) ?: (b === null)


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🤔 Какие готовые компоненты с готовым скоупом есть в Dagger Hilt и как модуль добавить к этой компоненте?

Hilt предоставляет компоненты для приложения, активностей, фрагментов, ViewModel и других уровней. Модуль подключается с помощью аннотации
@InstallIn, где указывается конкретный компонент, в рамках которого он будет использоваться.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
🤔 В каком потоке запускается самый обычный сервис?

Самый обычный сервис, который наследуется от класса Service, по умолчанию запускается в главном потоке приложения, который также называется UI-потоком (User Interface Thread). Это означает, что все операции, выполняемые в сервисе, включая методы onStartCommand(), onCreate(), и onBind(), выполняются в главном потоке. Если в сервисе будут выполняться длительные или ресурсоемкие операции, такие как сетевые запросы, обработка больших данных или выполнение сложных вычислений, это может привести к "зависанию" пользовательского интерфейса и появлению сообщений о том, что приложение не отвечает (ANR — Application Not Responding).

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
🤔 Из каких более важных компонентов состоит Compose?

Compose состоит из компонентов:
- Composable функции: описывают UI.
- State: управляет состоянием компонентов.
- Modifiers: применяются для настройки внешнего вида и поведения.
- Layouts: определяют структуру расположения элементов на экране.
- Recomposition: механизм обновления интерфейса при изменении состояния.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6👍1
🤔 Какие способы навигации знаешь?

В Android есть несколько способов навигации между экранами. Давай разберём основные.

🟠Activity-based навигация
Каждый экран – это отдельная Activity, переход осуществляется с помощью Intent.
val intent = Intent(this, SecondActivity::class.java)
startActivity(intent)


🟠Fragment-based навигация
Один Activity содержит несколько Fragment, навигация через FragmentManager.
supportFragmentManager.beginTransaction()
.replace(R.id.container, SecondFragment())
.addToBackStack(null)
.commit()


🟠Navigation Component (Jetpack)
Google рекомендует Navigation Component для удобной работы с Fragment.
findNavController().navigate(R.id.action_firstFragment_to_secondFragment)


🟠Bottom Navigation / Tab Navigation
Используется BottomNavigationView или TabLayout для переключения между экранами.
bottomNavigationView.setOnNavigationItemSelectedListener { item ->
when (item.itemId) {
R.id.home -> replaceFragment(HomeFragment())
R.id.profile -> replaceFragment(ProfileFragment())
}
true
}


🟠Drawer Navigation (Navigation Drawer)
Боковое меню (DrawerLayout) с пунктами навигации.
drawerLayout.openDrawer(GravityCompat.START)


🟠Deep Links и App Links
Навигация через ссылки (например, myapp://profile/123).
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<data android:scheme="myapp" android:host="profile"/>
</intent-filter>


🟠Navigation в Jetpack Compose
Используется NavHost и NavController.
NavHost(navController, startDestination = "home") {
composable("home") { HomeScreen(navController) }
composable("profile") { ProfileScreen(navController) }
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🤔 Знаешь, чем MVVM отличается от MVP?

В MVVM (Model-View-ViewModel) ViewModel отвечает за обработку данных и предоставление их View, не зная о её реализации, тогда как в MVP (Model-View-Presenter) Presenter активно управляет интерфейсом и логикой. В MVVM связь между View и ViewModel осуществляется через привязку данных, что делает интерфейс более реактивным и минимизирует прямую логику в View. MVP требует больше ручного связывания компонентов и имеет более явное разделение обязанностей между Presenter и View. MVVM часто предпочтительнее для приложений с богатым пользовательским интерфейсом, так как поддерживает более чистую архитектуру.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6👍1
🤔 В андроиде существуют мэпы, в которые можно положить примитивные типы?

Да! В 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]) // Длинный ключ


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
🤔 Что такое PendingIntent?

PendingIntent — это обёртка над Intent, позволяющая другим компонентам (например, системным) выполнить Intent от имени вашего приложения, даже если оно сейчас не активно.
Используется:
- В уведомлениях (NotificationManager).
- Для запуска BroadcastReceiver или Service.
- В AlarmManager.
Он играет роль разрешения: система может отложить выполнение кода, но с уже подтверждёнными правами.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4
🤔 Как определить изменение скорости работы программы после наших действий?

🟠Profile GPU Rendering
Этот инструмент показывает время, затраченное на отрисовку каждого кадра. Использование этого инструмента позволяет выявить "тяжелые" кадры и измерить улучшения после оптимизации.

1⃣Включите режим разработчика на устройстве.
2⃣Перейдите в "Настройки" -> "Для разработчиков".
3⃣Включите опцию "Profile GPU Rendering" и выберите "On screen as bars".
4⃣Запустите ваше приложение и наблюдайте за графиками. Зеленые линии указывают на время отрисовки, и ваша цель - оставаться ниже 16 мс (для 60 кадров в секунду).

🟠Android Profiler
Предоставляет набор инструментов для анализа производительности приложения.

1⃣ Откройте Android Studio и запустите ваше приложение.
2⃣Перейдите в "View" -> "Tool Windows" -> "Profiler".
3⃣Выберите ваше устройство и запущенное приложение.
4⃣Используйте вкладки CPU, Memory, Network и Energy для анализа различных аспектов производительности.
5⃣Сравните данные до и после оптимизации.

🟠Benchmarking
Создание и использование тестов производительности помогает количественно оценить улучшения. Вы можете использовать библиотеку Jetpack Benchmark для создания и выполнения тестов производительности.

🚩Пример использования Jetpack Benchmark:

1⃣Добавьте зависимости в build.gradle:
dependencies {
androidTestImplementation "androidx.benchmark:benchmark-junit4:1.1.0"
androidTestImplementation "androidx.test:runner:1.3.0"
androidTestImplementation "androidx.test:rules:1.3.0"
}


2⃣Создайте класс теста:
import androidx.benchmark.junit4.BenchmarkRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class ExampleBenchmark {
@get:Rule
val benchmarkRule = BenchmarkRule()

@Test
fun myFunctionBenchmark() {
benchmarkRule.measureRepeated {
// Вызов вашей функции или кода для тестирования производительности
myFunction()
}
}
}


🟠Logcat
Используйте журналирование для измерения времени выполнения определенных операций.
val startTime = System.currentTimeMillis()
// Ваш код
val endTime = System.currentTimeMillis()
Log.d("Performance", "Время выполнения: ${endTime - startTime} мс")


🟠StrictMode
StrictMode помогает обнаружить операции, которые могут замедлить работу приложения, такие как работа с сетью или базой данных в главном потоке.
if (BuildConfig.DEBUG) {
StrictMode.setThreadPolicy(
StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyLog()
.build()
)
StrictMode.setVmPolicy(
StrictMode.VmPolicy.Builder()
.detectAll()
.penaltyLog()
.build()
)
}


🟠Systrace
Systrace позволяет собирать и анализировать трассировки производительности системы, предоставляя детализированные данные о времени выполнения различных операций.

1⃣Включите режим разработчика на устройстве.
2⃣В "Настройки" -> "Для разработчиков" включите "Enable GPU Debug Layers".
3⃣Запустите команду adb shell am broadcast -a com.android.systemui.screenshot.ScreenshotService.ACTION_SYSTRACE.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥1
🤔 Зачем нужен класс Nothing?

Класс `Nothing` в Kotlin представляет тип, который не имеет значения и используется для обозначения невозможного кода, например, в функциях, которые всегда выбрасывают исключение или никогда не завершаются. Это полезно для обозначения точек кода, которые не должны быть достигнуты. `Nothing` позволяет более точно описывать типы функций и улучшает читаемость и безопасность кода. Он используется как "конечный" тип, который не возвращает значений.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8👍3
🤔 Можно ли получить в runtime доступ к типу дженерика?

По умолчанию нельзя, потому что дженерики стираются (Type Erasure) во время компиляции.
fun <T> printType(value: T) {
println(T::class.simpleName) // Ошибка! Нельзя использовать `T::class`
}


🚩Как получить тип дженерика? (`reified`)

Если используем inline fun, можно сделать дженерик "реальным" (reified).
inline fun <reified T> printType(value: T) {
println(T::class.simpleName) // Работает!
}

fun main() {
printType(123) // Int
printType("Hello") // String
printType(3.14) // Double
}


🚩Как получить тип дженерика в классе? (`KType`)

Если дженерик используется в классе, то reified не поможет.
class MyGenericClass<T>(private val type: KClass<T>) {
fun printType() {
println(type.simpleName) // Работает
}
}

fun main() {
val obj = MyGenericClass(String::class)
obj.printType() // String
}


🚩Как получить тип списка (`List<T>`) в `runtime`?

Для сложных дженериков (List<T>, Map<K, V>) используем typeOf<T>() (только с reified).
import kotlin.reflect.typeOf

inline fun <reified T> printGenericType() {
val type = typeOf<T>()
println(type) // List<Int>, Map<String, Boolean> и т. д.
}

fun main() {
printGenericType<List<Int>>() // kotlin.collections.List<kotlin.Int>
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
🤔 Что находится в ресурсах и какие данные в них можно хранить?

– drawable/ — изображения,
– layout/ — xml-макеты,
– values/ — строки, цвета, стили, размеры,
– raw/, assets/ — аудио, видео, JSON и прочее.
Хранятся данные, не изменяемые во время выполнения.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🔥1
🤔 Как класс-наследник оперирует функционалом класса-родителя?

Класс-наследник в Kotlin получает доступ к функционалу родительского класса через:
Наследование (:) — доступ ко всем open методам и свойствам.
Ключевое слово super — вызов методов родителя.
Переопределение (override) — изменение поведения.

🚩Наследование: доступ к методам и свойствам

Класс-наследник получает доступ ко всем open методам и свойствам родителя.
open class Animal(val name: String) {
fun eat() {
println("$name ест")
}
}

class Dog(name: String) : Animal(name)

fun main() {
val dog = Dog("Шарик")
dog.eat() // Шарик ест (метод унаследован)
}


🚩`super` – вызов методов родителя

Пример
open class Animal {
open fun makeSound() {
println("Животное издаёт звук")
}
}

class Dog : Animal() {
override fun makeSound() {
super.makeSound() // Вызываем метод родителя
println("Гав-гав!")
}
}

fun main() {
val dog = Dog()
dog.makeSound()
}


Вывод
Животное издаёт звук
Гав-гав!


🚩Переопределение (`override`)

Класс-наследник может изменить поведение родительского метода.
open class Animal {
open fun move() {
println("Животное двигается")
}
}

class Bird : Animal() {
override fun move() {
println("Птица летит") // Переопределяем метод
}
}

fun main() {
val bird = Bird()
bird.move() // Птица летит
}


🚩Вызов конструктора родителя (`super`)

Пример
open class Animal(val name: String)

class Dog(name: String, val breed: String) : Animal(name) {
fun info() {
println("Имя: $name, Порода: $breed") // Используем `name` из родителя
}
}

fun main() {
val dog = Dog("Бобик", "Лабрадор")
dog.info() // Имя: Бобик, Порода: Лабрадор
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🤔 Какое событие вызывается при нажатии юзера по экрану?

Система вызывает:
1. dispatchTouchEvent() — распределяет событие.
2. onTouchEvent() — обрабатывает вью, если не перехвачено.
3. onClick() — вызывается, если был ACTION_UP без движения.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3
🤔 Как расшифровывается xml?

XML — это eXtensible Markup Language (Расширяемый язык разметки).

🚩Что означает расшифровка?

eXtensible → Расширяемый (можно создавать свои теги).
Markup → Разметка (использует теги <tag> для структурирования данных).
Language → Язык (формат хранения и передачи данных).

🚩Где используется XML?

В Android:
Разметка UI (activity_main.xml).
Конфигурация (AndroidManifest.xml).
Ресурсы (strings.xml, colors.xml).

В веб-разработке:
Конфигурации (.xml файлы в серверных приложениях).
Форматы обмена данными (SOAP, RSS, SVG).

Пример XML-кода
<user>
<name>Алиса</name>
<age>25</age>
</user>


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
🤔 Какие примитивы есть в Kotlin, а какие в Java?

Java: byte, short, int, long, float, double, char, boolean.
Kotlin использует обёртки (Int, Double, Boolean и др.), которые компилируются в примитивы при необходимости.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🔥1