Kotlin | Вопросы собесов
2.57K subscribers
28 photos
960 links
Download Telegram
🤔 От какого объекта наследуются все классы в Java?

В Java все классы неявно наследуются от класса Object, если явно не указано другое наследование.
class MyClass {
// Неявно наследуется от Object
}

class MyClass2 extends Object {
// То же самое, просто указано явно
}


🚩Методы, унаследованные от `Object`

Класс Object содержит основные методы, доступные во всех классах:
class Person {
String name;

Person(String name) {
this.name = name;
}

@Override
public String toString() {
return "Person{name='" + name + "'}";
}
}

public class Main {
public static void main(String[] args) {
Person p = new Person("Alice");

System.out.println(p.toString()); // Person{name='Alice'}
System.out.println(p.hashCode()); // Хеш-код объекта
System.out.println(p.getClass()); // class Person
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
🤔 Отличие IntentService от Service

- Service работает в главном потоке — требует явного создания потоков.
- IntentService запускается в фоновом потоке автоматически, обрабатывает каждый Intent по очереди и сам завершает себя после выполнения.
Однако IntentService считается устаревшим — теперь предпочтительнее JobIntentService или WorkManager.


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

Да! В 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
👍3
🤔 Как можно понять, что класс является наследником?

Если он использует : и указывает имя другого класса или интерфейса. Также можно посмотреть в IDE или через is/instanceof в рантайме.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊7👍1🔥1
🤔 Можешь привести пример, когда android фреймворк использует паттерн Factory?

Да, Android Framework активно использует паттерн Factory в различных API. Один из самых известных примеров — LayoutInflater.

🚩Пример: `LayoutInflater` (Фабричный метод)

В Android для создания (инстанцирования) UI-компонентов из XML используется LayoutInflater, который реализует паттерн Factory Method. Вместо того чтобы вручную создавать объекты View, система предоставляет фабричный метод inflate(), который "производит" экземпляры View.

🚩Как работает?

В XML описан интерфейс.
LayoutInflater загружает XML и создает соответствующие объекты View.
Это абстрагирует создание UI-компонентов от разработчика.
val inflater = LayoutInflater.from(context)
val view = inflater.inflate(R.layout.custom_layout, parent, false)


🚩Другие примеры использования Factory в Android

🟠`MediaPlayer.create()`
Вместо MediaPlayer() напрямую используется MediaPlayer.create(context, R.raw.sound), который автоматически создаёт и настраивает объект.

🟠`PreferenceManager.getDefaultSharedPreferences()`
Позволяет получить SharedPreferences без необходимости вручную создавать экземпляр.

🟠`Fragment.instantiate()`
Фабричный метод для создания Fragment без явного вызова конструктора.

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

1.
Schedulers.io(): для ввода-вывода, работы с сетью или файлами.
2. Schedulers.computation(): для интенсивных вычислений, таких как обработка данных или рендеринг.
3. Schedulers.newThread(): для запуска новых потоков.
4. Schedulers.single(): для выполнения задач в одном потоке.
5. AndroidSchedulers.mainThread(): для работы с главным (UI) потоком на Android.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2👍1
Forwarded from easyoffer
Новая фича на easyoffer Автоотлики

Вы автоматически откликаетесь на подходящие вам вакансии. Попробуйте её бесплатно и начните получать больше предложений о работе.

🚀 Запуск занимаем всего 3 минуты, а экономит очень много времени
🛡 Это безопасно: easyoffer официально одобрен HeadHunter и прошел его модерацию.
🥷🏻 Автоотклик незаметен для рекртера. Автоотклик ничем не отличается от обычного отклика, который вы делаете вручную

Рекрутеры давно используют автоматизацию для поиска кандидатов. Так почему вы должны откликаться вручную?

💡Совет – Добавьте шаблон сопроводительного письма, чтобы откликаться на большее количество вакансий (на некоторые вакансии нельзя откликнуться без сопроводительного)

Попробовать бесплатно → https://easyoffer.ru/autoapply
🤔 Как в Ретрофите в гет методе поставить атрибут в путь в контретом месте?

В 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


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

В Android метод называется onStartCommand() — здесь происходит основная работа Service, если он не IntentService. В JobIntentService аналог — onHandleWork().


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2👍1
🤔 Как 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
👍2🔥1
🤔 Зачем нужны методы equals и hashCode?

Методы `equals()` и `hashCode()` в Kotlin и Java используются для сравнения объектов на равенство и для определения хэш-кода объекта, соответственно. Корректная реализация обоих методов необходима, чтобы обеспечить правильное функционирование объекта в коллекциях, таких как HashSet и HashMap.

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

Это компонент приложения, который предоставляет пользовательский интерфейс (UI), с которым пользователи могут взаимодействовать для выполнения различных действий, таких как набор номера телефона, просмотр фотографий, отправка электронной почты и т. д. Каждая активность представляет собой один экран с пользовательским интерфейсом. Если представить приложение как книгу, то активность будет одной страницей этой книги.

🚩Основное назначение

🟠Предоставление интерфейса пользователя
Основная задача — предоставить макет (layout), который будет содержать все элементы пользовательского интерфейса, такие как кнопки, текстовые поля, изображения и прочее, с которыми пользователь может взаимодействовать.

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

🟠Управление жизненным циклом
Android управляет активностями через заданный жизненный цикл, который определяет, как активность создается, запускается, останавливается и уничтожается. Разработчики могут переопределять методы жизненного цикла, чтобы добавить свою логику обработки для разных состояний активности.

🟠Переход между экранами
В приложении обычно есть несколько активностей, и он используется для перехода от одного экрана к другому. Для перехода между активностями используются интенты (Intents), которые не только помогают открыть новую активность, но и могут передавать данные между активностями.

🟠Взаимодействие с другими компонентами приложения
М
ожет взаимодействовать с другими компонентами приложения, такими как Services, BroadcastReceivers, и ContentProviders, используя интенты и другие механизмы Android для межкомпонентного взаимодействия.

class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}


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

Базовый класс — это Any. Он является корнем иерархии типов. Все классы неявно наследуются от него, если не указано другое.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2👍1💊1
🤔 Почему могут быть проблемы со списками в 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) // [Хлеб, Молоко, Яйца]
}


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

Списки — это ссылочные типы, и если в data class вложен изменяемый список (MutableList), то:
- при копировании через copy() копируется ссылка, а не сам список;
- equals и hashCode могут работать некорректно, если список изменился после создания.


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

В Android для наложения (перекрытия) элементов друг на друга используется FrameLayout или Box (в Jetpack Compose).

🚩FrameLayout (в XML и View)

FrameLayout — это контейнер, в котором все вложенные элементы располагаются в левом верхнем углу, но при этом могут накладываться друг на друга.
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">

<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/background" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Наложенный текст"
android:textSize="24sp"
android:textColor="#FFFFFF"
android:layout_gravity="center"/>
</FrameLayout>


🚩Box (в Jetpack Compose)

В Jetpack Compose аналогом FrameLayout является Box. Он также позволяет располагать элементы друг над другом.
Box(
modifier = Modifier.fillMaxSize()
) {
Image(
painter = painterResource(id = R.drawable.background),
contentDescription = "Фон",
modifier = Modifier.fillMaxSize()
)

Text(
text = "Наложенный текст",
fontSize = 24.sp,
color = Color.White,
modifier = Modifier.align(Alignment.Center)
)
}


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

Через:
- primary constructor + init блок,
- secondary constructor с ключевым словом constructor,
- значения по умолчанию в параметрах.


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

В Android можно создавать интерфейс без XML с помощью Jetpack Compose или программного кода (View в Kotlin/Java).

🚩Jetpack Compose — современный декларативный подход

Jetpack Compose — это новый способ создания UI в Android без XML, основанный на Kotlin.
@Composable
fun GreetingScreen() {
Column(
modifier = Modifier.fillMaxSize().padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "Привет, мир!", fontSize = 24.sp)
Button(onClick = { println("Кнопка нажата") }) {
Text("Нажми меня")
}
}
}

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
GreetingScreen()
}
}
}


🚩Создание UI через View в Kotlin (старый способ)

Если Jetpack Compose не подходит, можно создать интерфейс программно, без XML, используя стандартные View.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

// Создаём контейнер (LinearLayout)
val layout = LinearLayout(this).apply {
orientation = LinearLayout.VERTICAL
gravity = Gravity.CENTER
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
}

// Создаём текст
val textView = TextView(this).apply {
text = "Привет, мир!"
textSize = 24f
setTextColor(Color.BLACK)
}

// Создаём кнопку
val button = Button(this).apply {
text = "Нажми меня"
setOnClickListener {
textView.text = "Кнопка нажата!"
}
}

// Добавляем элементы в контейнер
layout.addView(textView)
layout.addView(button)

// Устанавливаем UI
setContentView(layout)
}
}


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

Handler используется вместе с Looper, чтобы поставить задачу в очередь исполнения в определённом потоке. Если ты создаёшь Handler, привязанный к конкретному Looper, все отправленные сообщения и Runnable выполняются по очереди, синхронно внутри этого потока, но асинхронно по отношению к другим потокам. То есть Handler помогает упорядочить выполнение задач внутри одного потока.

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

В 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]


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🤔 Как сборщик мусора понимает, что объект можно уничтожить?

GC отслеживает достижимость объектов из корневых точек (stack, static, thread references). Если объект:
- Не имеет ни одной активной ссылки
- Не достижим по цепочке ссылок
…то он считается неиспользуемым и может быть удалён.
Алгоритмы: mark-and-sweep, tracing, generational collection.


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