- Жестовое управление.
- Поддержка ML Kit и нейросетевых API.
- Adaptive Battery и Adaptive Brightness.
- App Actions и предиктивные предложения.
- Поддержка notch-экранов (Display Cutout).
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4😁2
Бранчинг (ветвление) — это способ управления кодом в Git, когда разработчики работают в отдельных ветках (
branches). Основные стратегии бранчинга
Git Flow
GitHub Flow
GitLab Flow
Trunk-Based Development
Основные ветки:
main (стабильная версия, релизы). develop (основная ветка разработки). Временные ветки:
feature/* (новые фичи, мерджатся в develop). release/* (готовится релиз, тестирование, фикс багов). hotfix/* (критические фиксы в main). Схема Git Flow:
main ──── hotfix ─▶️ merge ────▶️ main
│
├── develop ─▶️ release ─▶️ merge ─▶️ main
│ │
├── feature/1
├── feature/2
Только две основные ветки:
main (всегда стабильная версия). Фичи разрабатываются в
feature/* и сразу мерджатся в main. Деплой возможен сразу после мерджа в
main. Схема GitHub Flow
main ────▶️ feature/1 ─▶️ merge ─▶️ main ─▶️ deploy
└── feature/2 ─▶️ merge ─▶️ main ─▶️ deploy
main – стабильная ветка (готовая к продакшену). develop (опционально) – если нужно тестирование перед main. feature/* – для разработки новых фич. production, staging – если нужно разделение сред. hotfix/* – фиксы продакшена. main ────▶️ production
│
├── staging ───▶️ merge ─▶️ main
│
├── feature/1 ─▶️ merge ─▶️ staging
├── feature/2 ─▶️ merge ─▶️ staging
Разработчики работают прямо в
main, без feature/* веток. - Коммиты в
main маленькие и частые. - Используются Feature Flags (фичи включаются/выключаются динамически).
Схема Trunk-Based
main ────▶️ commit ─▶️ commit ─▶️ commit ─▶️ deploy
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥1
- Асинхронно (с отложенным исполнением):
commitNow() — выполняется немедленно в текущем потоке. Используется редко (например, в setup-методах).
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
😁5👍1🔥1👀1
Да, ошибки (
Exceptions) обрабатываются по-разному в launch и async! launch сразу выбрасывает исключение, и если нет try-catch, корутина завершает родительский CoroutineScope. fun main() = runBlocking {
launch {
println("Начало работы")
throw RuntimeException("Ошибка в launch!")
}
delay(100) // ❌ Код не выполнится, так как `launch` упадёт
println("Этот код не выполнится")
}Вывод в консоль
Начало работы
Exception in thread "main" java.lang.RuntimeException: Ошибка в launch!
Решение
Использовать
try-catch внутри launch. launch {
try {
throw RuntimeException("Ошибка в launch!")
} catch (e: Exception) {
println("Ошибка поймана: ${e.message}")
}
}В
async ошибка не выбрасывается сразу, а сохраняется в Deferred<T>. Она появится только при вызове await(). fun main() = runBlocking {
val deferred = async {
println("Начало работы async")
throw RuntimeException("Ошибка в async!")
}
delay(100) // ✅ Код выполнится, так как ошибка пока не выброшена
println("Этот код выполнится")
deferred.await() // 💥 Ошибка падает только здесь!
}Вывод в консоль
Начало работы async
Этот код выполнится
Exception in thread "main" java.lang.RuntimeException: Ошибка в async!
Решение
Использовать
try-catch при await(). try {
deferred.await()
} catch (e: Exception) {
println("Ошибка поймана: ${e.message}")
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4👍3❤1
Гарантируется только в том случае, если структура данных поддерживает порядок (например, List, LinkedList).
Если коллекция неупорядоченная (например, HashSet, HashMap.keySet()), порядок может быть произвольным и не повторяться.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🔥1
Передача фото в редактор зависит от типа редактора:
1. Внешний редактор (например, Google Photos, Snapseed).
2. Встроенный редактор внутри приложения.
Если редактор — другое приложение, используем
Intent.ACTION_EDIT. Как передать фото в редактор?
fun openPhotoEditor(context: Context, uri: Uri) {
val intent = Intent(Intent.ACTION_EDIT).apply {
setDataAndType(uri, "image/*")
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) // Разрешение на чтение
}
context.startActivity(Intent.createChooser(intent, "Выберите редактор"))
}Если редактор — внутри приложения, можно передавать фото через
Intent с Uri. Отправка фото в редактор
fun openEditor(context: Context, photoFile: File) {
val uri = FileProvider.getUriForFile(context, "${context.packageName}.fileprovider", photoFile)
val intent = Intent(context, PhotoEditorActivity::class.java).apply {
putExtra("PHOTO_URI", uri.toString())
}
context.startActivity(intent)
}Получение фото в редакторе (
PhotoEditorActivity)class PhotoEditorActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val uriString = intent.getStringExtra("PHOTO_URI")
val uri = uriString?.let { Uri.parse(it) }
uri?.let {
imageView.setImageURI(it) // Показываем фото
}
}
}Если фото уже в памяти (
byte[]), можно передать его как Parcelable. Отправка
val bitmap = ... // Получили Bitmap
val byteArray = ByteArrayOutputStream().apply {
bitmap.compress(Bitmap.CompressFormat.PNG, 100, this)
}.toByteArray()
val intent = Intent(context, PhotoEditorActivity::class.java).apply {
putExtra("PHOTO_BYTES", byteArray)
}
context.startActivity(intent)
Получение
val byteArray = intent.getByteArrayExtra("PHOTO_BYTES")
byteArray?.let {
val bitmap = BitmapFactory.decodeByteArray(it, 0, it.size)
imageView.setImageBitmap(bitmap)
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
- Можно использовать SurfaceView — он предоставляет отдельный буфер, который можно обновлять вне основного потока.
- Также используется Canvas через SurfaceHolder.lockCanvas().
Подходит для игр, видео или сложной анимации.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4
Nothing — это специальный bottom type (нижний тип), который означает: Функция никогда не возвращает результат (
throw, error()). Код после
Nothing недостижим. fun fail(): Nothing {
throw IllegalStateException("Ошибка!") // Никогда не возвращает значение
}Все классы в Kotlin могут иметь инстансы (объекты), кроме
Nothing. Nothing нельзя создать (instantiate), потому что он не имеет конструктора. Любая переменная типа
Nothing просто не существует. val x: Nothing = Nothing() // ❌ Ошибка: у Nothing нет конструктора
Используется в
throwfun fail(): Nothing = throw IllegalArgumentException("Ошибка")Используется в
TODO()fun getData(): String {
TODO("Функция ещё не реализована")
}Используется в
if-else, где один вариант throwfun getValue(x: Int): String {
return if (x > 0) "Позитивное число" else throw IllegalArgumentException("Отрицательное!")
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2❤1
Forwarded from easyoffer
⏳ Осталось всего 14 дней до завершения краудфандинга
Сейчас самое подходящее время подключиться, если вы ждали или откладывали:
Все, кто поддержат проект сейчас, до релиза, получат:
🚀 PRO-доступ на 1 год по цене месячной подписки
➕ Бета-доступ к EasyOffer 2.0 (конец мая)
👉 Поддержать: https://planeta.ru/campaigns/easyoffer
Сейчас самое подходящее время подключиться, если вы ждали или откладывали:
Все, кто поддержат проект сейчас, до релиза, получат:
🚀 PRO-доступ на 1 год по цене месячной подписки
➕ Бета-доступ к EasyOffer 2.0 (конец мая)
👉 Поддержать: https://planeta.ru/campaigns/easyoffer
Примеры в Java:
- Serializable — объект можно сериализовать.
- Cloneable — объект можно клонировать.
- Remote — используется для удалённых вызовов.
- RandomAccess — для коллекций с быстрым доступом по индексу.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3
Сборка Android-приложения проходит несколько этапов:
Компиляция (
.kt/.java → .class → .dex) Объединение ресурсов (
XML, PNG → R.java) Сборка APK/AAB
Подписывание и оптимизация
Установка и запуск на устройстве
Компиляция Kotlin/Java в байткод JVM (
.class) Kotlin-код (
.kt) → Java-байткод (.class) Java-код (
.java) → .class - Используются компиляторы:
-
kotlinc (Kotlin Compiler) -
javac (Java Compiler) // Kotlin-код (MainActivity.kt)
fun main() {
println("Привет, Android!")
}
kotlinc MainActivity.kt -d MainActivity.class
Преобразование
.class в `.dex* Android не использует байткод JVM, а преобразует
.class в Dalvik Executable (.dex). d8 MainActivity.class --output classes.dex
Android Gradle Plugin (AGP) обрабатывает ресурсы
-
res/layout/*.xml → UI файлы -
res/drawable/*.png → Иконки -
AndroidManifest.xml → Метаинформация public final class R {
public static final class layout {
public static final int activity_main = 0x7f0a0000;
}
}APK (старый формат) и AAB (новый формат Google Play)
classes.dex + res/ + AndroidManifest.xml объединяются Проходит обфускация (
ProGuard / R8) APK/AAB упаковывается в ZIP-архив
zipalign -v 4 app.apk signed_app.apk
APK/AAB должен быть подписан перед установкой
apksigner sign --ks my-release-key.jks --out signed_app.apk app-release.apk
Установка и запуск
adb install signed_app.apk
adb shell am start -n com.example.app/.MainActivity
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4👍1
1. Strong Reference (сильная ссылка): защищает объект от удаления. Пока существует сильная ссылка, объект остаётся в памяти.
2. Weak Reference (слабая ссылка): объект может быть удалён сборщиком мусора, даже если на него есть слабая ссылка.
3. Soft Reference (мягкая ссылка): объект удаляется только при нехватке памяти.
4. Phantom Reference (фантомная ссылка): используется для выполнения действий после удаления объекта, объект недоступен через эту ссылку.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥1
APK (Android Package) — это архив с кодом приложения, ресурсами и манифестом.
Приложение должно быть подписано, чтобы его можно было установить на устройство.
- Это черновая версия APK, которая не имеет цифровой подписи.
- Такой APK можно запустить только в эмуляторе или при отладке (
debug build). - Google Play не принимает неподписанные APK.
При сборке
debug-версии в Android Studio: gradlew assembleDebug
Попытка установить неподписанный APK
adb install app-unsigned.apk
Ошибка
Failure [INSTALL_PARSE_FAILED_NO_CERTIFICATES]
- Подписанный APK содержит цифровую подпись, которая гарантирует, что код не был изменён.
- Android проверяет ключ подписи перед установкой.
Google Play требует подписанный APK или AAB.
Как подписать APK вручную?
apksigner sign --ks my-release-key.jks --out app-signed.apk app-unsigned.apk
Подпись APK гарантирует*
Целостность → код не был изменён после сборки.
Подлинность → приложение подписано разработчиком, а не злоумышленником.
Обновления → только приложения с тем же ключом могут обновлять старую версию.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2💊1
- a == b → true (распаковка и сравнение значений)
- a1 == b1 → true (аналогично)
Но: Integer a = 128; Integer a1 = 128; a == a1 → false, т.к. кэширование Integer до 127.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊9👍1🔥1
Forwarded from easyoffer
🎉 Easyoffer 2.0 — самый успешный краудфандинг в истории рунета в категории "Технологии"!
Мы это сделали! За считанные часы после старта, благодаря вашей поддержке, проект не просто стартовал — он взлетел.
💸 Собрано: 2 276 840 рублей
Это не просто цифра — это ваше доверие, ваша вера в идею, и ваша инвестиция в будущее карьеры сотен (а скоро — тысяч) специалистов.
💼 Благодаря этой сумме мы уже:
— Наняли ещё пару разработчиков и аналитиков
— Запустили активный сбор и разметку новых данных
— Ускорили разработку и подняли планку качества
Спасибо каждому, кто поверил в нас на старте! Дальше — только масштабирование и развитие. Мы строим сервис, который станет must-have для всех, кто ищет работу в IT.
👉 Присоединяйтесь сейчас — это только начало.
Мы это сделали! За считанные часы после старта, благодаря вашей поддержке, проект не просто стартовал — он взлетел.
💸 Собрано: 2 276 840 рублей
Это не просто цифра — это ваше доверие, ваша вера в идею, и ваша инвестиция в будущее карьеры сотен (а скоро — тысяч) специалистов.
💼 Благодаря этой сумме мы уже:
— Наняли ещё пару разработчиков и аналитиков
— Запустили активный сбор и разметку новых данных
— Ускорили разработку и подняли планку качества
Спасибо каждому, кто поверил в нас на старте! Дальше — только масштабирование и развитие. Мы строим сервис, который станет must-have для всех, кто ищет работу в IT.
👉 Присоединяйтесь сейчас — это только начало.
В многомодульных проектах каждый модуль может иметь свой
AndroidManifest.xml, чтобы: Задавать зависимости (
uses-permission, uses-feature) для конкретного модуля. Определять компоненты (
Activity, Service, BroadcastReceiver) для каждого модуля. Автоматически объединять манифесты всех модулей в
AndroidManifest.xml главного (app) модуля. При сборке Gradle автоматически сливает (
merge) все AndroidManifest.xml в один итоговый файл. app/
├── src/main/AndroidManifest.xml ← Главный манифест
├── java/com/example/MainActivity.kt
├── res/
├── build.gradle
feature_login/
├── src/main/AndroidManifest.xml ← Манифест модуля `login`
├── java/com/example/login/LoginActivity.kt
├── res/
├── build.gradle
feature_chat/
├── src/main/AndroidManifest.xml ← Манифест модуля `chat`
├── java/com/example/chat/ChatActivity.kt
├── res/
├── build.gradle
При сборке манифесты модулей сливаются в манифест главного модуля.
<manifest package="com.example.app">
<application>
<activity android:name=".MainActivity" />
</application>
</manifest>
feature_login (feature_login/src/main/AndroidManifest.xml) <manifest>
<application>
<activity android:name=".login.LoginActivity" />
</application>
</manifest>
feature_chat (feature_chat/src/main/AndroidManifest.xml) <manifest>
<application>
<activity android:name=".chat.ChatActivity" />
</application>
</manifest>
После объединения итоговый
AndroidManifest.xml выглядит так <manifest package="com.example.app">
<application>
<activity android:name=".MainActivity" />
<activity android:name=".login.LoginActivity" />
<activity android:name=".chat.ChatActivity" />
</application>
</manifest>
Например, модуль
camera требует CAMERA, но другие модули — нет. <uses-permission android:name="android.permission.CAMERA" />
Каждый модуль добавляет только свои компоненты (например,
LoginActivity в feature_login). Например, модуль
feature_map использует Google Maps, но feature_login — нет. <uses-library android:name="com.google.android.maps" />
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
- Обобщённые классы (class Box<T>)
- Обобщённые методы (<T> void print(T t))
- Ограничения (extends, super) — для указания границ типов
- Сырые типы (List без параметра — deprecated)
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊3🔥1
Разделение UI и бизнес-логики делает код понятнее, тестируемее и проще в поддержке.
Это ключевой принцип чистой архитектуры (Clean Architecture) и паттернов MVP, MVVM, MVI.
Плохой код (UI + логика в
Activity) class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val button = findViewById<Button>(R.id.button)
button.setOnClickListener {
val result = fetchData() // ❌ Логика в UI
button.text = result
}
}
fun fetchData(): String {
return "Данные с сервера" // ❌ Тут должна быть ViewModel
}
}Разделим код на
Activity + ViewModel MainActivity (только UI) class MainActivity : AppCompatActivity() {
private val viewModel: MainViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val button = findViewById<Button>(R.id.button)
viewModel.text.observe(this) { text ->
button.text = text // ✅ UI обновляется из ViewModel
}
button.setOnClickListener {
viewModel.loadData() // ✅ Вызываем бизнес-логику
}
}
}MainViewModel (бизнес-логика) class MainViewModel : ViewModel() {
private val _text = MutableLiveData<String>()
val text: LiveData<String> = _text
fun loadData() {
_text.value = "Данные с сервера" // ✅ UI не знает, откуда данные
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Forwarded from easyoffer
Что такое PRO-подписка на easyoffer 2.0?
easyoffer PRO — это не просто доступ к базе, а полноценный инструмент для получения оффера.
🧠 База вопросов с собеседований
+ Анализ на основе 4,000 собеседований
+ Вероятность встречи каждого вопроса
+ Фильтрация по грейдам, компаниям, типам интервью
+ Примеры ответов: текстовые и видео
+ Готовьтесь к собеседованию в конкретную компанию
🛠 Тренажер "Проработка вопросов"
+ Флеш-карточки + интервальные повторения
+ Персональная система показа карточек в зависимости от ваших ответов
+ Упор на наиболее частые вопросы
+ Фокус на слабые места и быстрый прогресс
🎭 Тренажер "Реальное собеседование"
+ Сценарии на основе реальных интервью
+ Подготовка к конкретным компаниям
+ Итоговая статистика: прошёл/не прошёл
🧩 База задач с собеседований
+ Live-coding и System Design задачи
+ Оценка вероятности встречи задачи
+ Подготовка к задачам по конкретным компаниям
📋 База тестовых заданий
+ Задания из реальных вакансий
+ Фильтрация по технологиям и грейдам
+ Лучшие решения в доступе
📈 Тренды технологий в вакансиях
+ Топ-100 навыков, которые требуют компании
+ Динамика популярности технологий
+ Фильтрация по грейдам
🎁 Специальная цена до релиза:
3200 руб. за целый год
Сейчас PRO на 1 год стоит как будет стоить 1 месяц после релиза. Покупка также открывает доступ к закрытому бета-тестированию.
+ Вы можете активировать подписку в любой момент, например, когда начнете искать работу.
Предзаказ здесь: https://planeta.ru/campaigns/easyoffer
📌 Цена поднимется сразу после запуска.
Если вы хотите перестать угадывать, что спросят на собеседовании, и начать точечно готовиться на основе реальных данных — easyoffer PRO именно для вас.
Экономьте время. Получайте оффер легко.
easyoffer PRO — это не просто доступ к базе, а полноценный инструмент для получения оффера.
🧠 База вопросов с собеседований
+ Анализ на основе 4,000 собеседований
+ Вероятность встречи каждого вопроса
+ Фильтрация по грейдам, компаниям, типам интервью
+ Примеры ответов: текстовые и видео
+ Готовьтесь к собеседованию в конкретную компанию
🛠 Тренажер "Проработка вопросов"
+ Флеш-карточки + интервальные повторения
+ Персональная система показа карточек в зависимости от ваших ответов
+ Упор на наиболее частые вопросы
+ Фокус на слабые места и быстрый прогресс
🎭 Тренажер "Реальное собеседование"
+ Сценарии на основе реальных интервью
+ Подготовка к конкретным компаниям
+ Итоговая статистика: прошёл/не прошёл
🧩 База задач с собеседований
+ Live-coding и System Design задачи
+ Оценка вероятности встречи задачи
+ Подготовка к задачам по конкретным компаниям
📋 База тестовых заданий
+ Задания из реальных вакансий
+ Фильтрация по технологиям и грейдам
+ Лучшие решения в доступе
📈 Тренды технологий в вакансиях
+ Топ-100 навыков, которые требуют компании
+ Динамика популярности технологий
+ Фильтрация по грейдам
🎁 Специальная цена до релиза:
3200 руб. за целый год
Сейчас PRO на 1 год стоит как будет стоить 1 месяц после релиза. Покупка также открывает доступ к закрытому бета-тестированию.
+ Вы можете активировать подписку в любой момент, например, когда начнете искать работу.
Предзаказ здесь: https://planeta.ru/campaigns/easyoffer
📌 Цена поднимется сразу после запуска.
Если вы хотите перестать угадывать, что спросят на собеседовании, и начать точечно готовиться на основе реальных данных — easyoffer PRO именно для вас.
Экономьте время. Получайте оффер легко.
BroadcastReceiver принимает сообщения (интенты) от системы или приложений — например, при смене сети или получения SMS. ContentProvider предоставляет структурированный способ доступа к данным, используется для обмена данными между приложениями (например, контакты, галерея).
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
В
data class могут возникнуть проблемы со списками при использовании: Методов
copy() – список не копируется, а передаётся по ссылке. Методов
equals() и hashCode() – List сравнивается по элементам, что может быть медленно. Mutable списков (
MutableList) – изменения внутри списка изменяют все копии объекта. 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 (разные объекты)
}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()
}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
👍1🔥1