Kotlin | Вопросы собесов
2.56K subscribers
29 photos
971 links
Download Telegram
🤔 Из каких более важных компонентов состоит 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
🤔 Как с MVI обрабатывать события, которые не нужно хранить?

В MVI (Model-View-Intent) есть проблема: события, которые не нужно хранить в State, могут повторно отобразиться при пересоздании экрана (например, при повороте экрана или навигации назад).
Показ Toast / Snackbar
Навигация (openScreen())
Ошибки, которые нужно показать один раз

🟠Используем `SingleLiveEvent` (для ViewModel)
Это LiveData, которая отправляет событие только один раз и не пересылает его новым подписчикам.
class SingleLiveEvent<T> : MutableLiveData<T>() {
private val pending = AtomicBoolean(false)

override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
super.observe(owner) { value ->
if (pending.compareAndSet(true, false)) {
observer.onChanged(value)
}
}
}

override fun setValue(value: T?) {
pending.set(true)
super.setValue(value)
}
}


ViewModel с SingleLiveEvent
class MyViewModel : ViewModel() {
val eventShowToast = SingleLiveEvent<String>()

fun onButtonClicked() {
eventShowToast.value = "Привет, это Toast!"
}
}


Activity/Fragment подписывается
viewModel.eventShowToast.observe(viewLifecycleOwner) { message ->
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
}


🟠Используем `SharedFlow` (современный подход)
В StateFlow все события хранятся в State (что не подходит для одноразовых событий).
Вместо этого используем SharedFlow с replay = 0, чтобы событие не повторялось.

ViewModel с SharedFlow
class MyViewModel : ViewModel() {
private val _events = MutableSharedFlow<UiEvent>()
val events = _events.asSharedFlow()

fun onButtonClicked() {
viewModelScope.launch {
_events.emit(UiEvent.ShowToast("Привет, это Toast!"))
}
}
}

sealed class UiEvent {
data class ShowToast(val message: String) : UiEvent()
object NavigateToNextScreen : UiEvent()
}


Подписка в UI:
lifecycleScope.launchWhenStarted {
viewModel.events.collect { event ->
when (event) {
is UiEvent.ShowToast -> Toast.makeText(context, event.iss.onessage, Toast.LENGTH_SHORT).show()
is UiEvent.NavigateToNextScreen -> findNavController().navigate(R.id.nextFragment)
}
}
}


🟠Используем `EventWrapper` (обходной путь для StateFlow)
Если в State всё-таки нужно хранить событие, но не показывать его повторно, можно использовать EventWrapper.
class EventWrapper<out T>(private val content: T) {
private var hasBeenHandled = false

fun getContentIfNotHandled(): T? {
return if (hasBeenHandled) null else {
hasBeenHandled = true
content
}
}
}


ViewModel с StateFlow:
data class UiState(val message: EventWrapper<String>? = null)

class MyViewModel : ViewModel() {
private val _state = MutableStateFlow(UiState())
val state = _state.asStateFlow()

fun onButtonClicked() {
_state.value = UiState(message = EventWrapper("Привет, это Toast!"))
}
}


UI подписывается и проверяет EventWrapper:
viewModel.state.collect { state ->
state.message?.getContentIfNotHandled()?.let { message ->
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
🤔 В чём отличие Android 4 и 5?

Android 5 (Lollipop) по сравнению с Android 4 (KitKat):
- Появился Material Design.
- Новая ART (Android Runtime) вместо Dalvik.
- Поддержка 64-битных устройств.
- Project Volta — улучшения в энергопотреблении.
- Многопользовательская поддержка на телефонах.
- Улучшенная работа с уведомлениями.


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

Класс Object (в Java) и Any (в Kotlin/Scala/Swift) включает:
- equals(Object obj)
- hashCode()
- toString()
- getClass()
- wait()
- notify()
- notifyAll()
- clone()
- finalize() (устаревший)


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊5🔥2
🤔 В чем различие Default диспатчер и IO диспатчер?

В Kotlin Coroutines есть несколько диспетчеров (Dispatchers), но Default и IO используются чаще всего.

🚩Главное различие:

Dispatchers.Default — для тяжёлых вычислений (CPU-операции).
Dispatchers.IO — для операций ввода-вывода (сеть, файлы, БД).

🟠`Dispatchers.Default` – для сложных вычислений (CPU-bound)
Этот диспетчер используется, если код загружает процессор (например, сложные вычисления).
import kotlinx.coroutines.*

fun main() = runBlocking {
launch(Dispatchers.Default) {
val result = heavyComputation()
println("Результат: $result")
}
}

suspend fun heavyComputation(): Int {
delay(1000)
return (1..1_000_000).sum()
}


🟠`Dispatchers.IO` – для работы с файлами, сетью, БД (IO-bound)
Этот диспетчер оптимизирован для ввода-вывода (I/O): работа с файлами, сетью, БД.
import kotlinx.coroutines.*
import java.io.File

fun main() = runBlocking {
launch(Dispatchers.IO) {
val text = File("data.txt").readText()
println("Файл прочитан: $text")
}
}


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

- Использование блоков synchronized,
- Мьютексы,
- java.util.concurrent (например, ConcurrentHashMap),
- Иммутабельные объекты,
- Логика через ExecutorService.


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

Сильная ссылка - это ссылка, которая напрямую указывает на объект и предотвращает его сборку сборщиком мусора.

🚩Основные подходы

🟠WeakReference
Использование слабых ссылок (WeakReference) позволяет определить, был ли объект освобожден сборщиком мусора.
🟠ObjectWatcher (в LeakCanary)
LeakCanary использует ObjectWatcher для отслеживания объектов. Если объект не освобожден, ObjectWatcher уведомляет об утечке.

import java.lang.ref.WeakReference;

public class MemoryLeakExample {

public static void main(String[] args) {
// Создание объекта
MyObject myObject = new MyObject();

// Создание слабой ссылки на объект
WeakReference<MyObject> weakRef = new WeakReference<>(myObject);

// Удаление сильной ссылки
myObject = null;

// Вызов сборщика мусора
System.gc();

// Проверка, была ли слабая ссылка освобождена
if (weakRef.get() == null) {
System.out.println("Object has been garbage collected");
} else {
System.out.println("Object is still alive");
}
}

static class MyObject {
// Некоторая логика класса
}
}


🚩Понимание, что объект не используется

🟠Нет сильных ссылок
Убедитесь, что на объект нет сильных ссылок. Только слабые, мягкие или фантомные ссылки не предотвращают сборку объекта.
🟠Сборка мусора
Если объект становится недоступным через сильные ссылки, сборщик мусора может его освободить.
🟠Проверка с помощью WeakReference
Слабые ссылки могут быть использованы для проверки того, был ли объект освобожден.

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

- ArrayList, LinkedList,
- HashSet, TreeSet, LinkedHashSet,
- HashMap, TreeMap, LinkedHashMap,
- PriorityQueue, ArrayDeque.


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