Kotlin | Вопросы собесов
2.56K subscribers
29 photos
967 links
Download Telegram
🤔 Какой самый экономичный тип графического файла?

Формат WebP является наиболее экономичным с точки зрения сжатия без потери качества. Он лучше по сжатию, чем PNG или JPEG, поддерживает прозрачность и используется во многих Android-приложениях.


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

🟠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
👍1
🤔 Чем background service отличается от foreground service?

– Background service работает в фоне, может быть остановлен системой при нехватке ресурсов.
– Foreground service требует уведомление и имеет приоритет, не убивается системой просто так.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
🤔 Чем отличаются 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()
}


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

1. Использовать onSaveInstanceState и передавать данные в Bundle.
2. Сохранить данные в ViewModel, чтобы они переживали пересоздание.
3. Сохранить данные в локальном хранилище, например, SharedPreferences.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
🤔 Для проектов в которых есть несколько модулей, там может быть много Android Manifest'ов, для чего это делается?

В многомодульных проектах каждый модуль может иметь свой 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>


🚩Зачем модулям свой `AndroidManifest.xml`?

🟠Разные разрешения (`uses-permission`) для каждого модуля
Например, модуль camera требует CAMERA, но другие модули — нет.
<uses-permission android:name="android.permission.CAMERA" />


🟠Разные `Activity`, `Service`, `BroadcastReceiver` в каждом модуле
Каждый модуль добавляет только свои компоненты (например, 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
🤔 Какая особенность у Data Class относительно других Kotlin Classes?

Data Class автоматически генерирует equals, hashCode, toString, copy, и componentN функции. Они удобны для хранения данных и значительно упрощают работу с неизменяемыми структурами.


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

Лямбда-выражения представляют собой компактный способ представления анонимных функций, который особенно полезен для создания коротких блоков выполнения кода, предназначенных для последующей передачи другим функциям. Лямбды широко используются для упрощения работы с коллекциями, потоками данных, асинхронным кодом и в ситуациях, где требуется функциональный интерфейс.

🚩Лямбда-выражения

Были введены в Java 8 и являются частью усилий по добавлению функциональных возможностей в язык. Лямбды в Java чаще всего используются с функциональными интерфейсами, которые являются интерфейсами с одним абстрактным методом.
(parameters) -> expression


или
(parameters) -> { statements; }


🚩Лямбда-выражения

Поддерживает более гибкие и выразительные лямбды по сравнению с Java. Лямбды могут использоваться как с функциональными интерфейсами, так и в качестве части синтаксиса языка, благодаря чему Kotlin особенно удобен для функционального программирования.
{ parameters -> code body }


🚩Примеры

Лямбда без параметров
{ println("Hello, World!") }  


Лямбда с одним параметром
{ a: Int -> a * a }   


Лямбда с несколькими параметрами
{ a: Int, b: Int -> a + b }   


Лямбда с телом, содержащим несколько выражений
      { s: String ->
println(s)
s.length
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🤔 Что значит volatile переменная?

volatile гарантирует, что все потоки видят актуальное значение переменной, а не её локальную копию из кеша. Это не делает операцию атомарной, но обеспечивает согласованность чтения/записи.


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

TransactionTooLargeException — это исключение, которое возникает, если передаваемые данные превышают лимит 1MB в Binder.
Чаще всего ошибка появляется при передаче больших объектов через Intent, Bundle, `onSaveInstanceState().

🚩Как воспроизвести `TransactionTooLargeException`?

Передача большого Bitmap через Intent (ОШИБКА!)
val bitmap: Bitmap = getLargeBitmap() //  Очень большой объект

val intent = Intent(this, ImageActivity::class.java)
intent.putExtra("image", bitmap) // Ошибка: TransactionTooLargeException

startActivity(intent)


Ошибка
android.os.TransactionTooLargeException: data parcel size 2MB is larger than 1MB


🚩Как избежать `TransactionTooLargeException`?

Использовать FileProvider и Uri вместо Bitmap
val file = File(context.cacheDir, "image.png")
file.outputStream().use {
bitmap.compress(Bitmap.CompressFormat.PNG, 100, it)
}

val uri = FileProvider.getUriForFile(context, "${context.packageName}.fileprovider", file)
val intent = Intent(this, ImageActivity::class.java).apply {
putExtra("image_uri", uri.toString())
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
startActivity(intent)


🚩Использовать `ViewModel` вместо `onSaveInstanceState()`

Ошибка: сохранение больших данных в onSaveInstanceState()
override fun onSaveInstanceState(outState: Bundle) {
outState.putSerializable("largeData", myLargeObject) // ОШИБКА!
super.onSaveInstanceState(outState)
}


Решение → Используем ViewModel, чтобы хранить данные в памяти:
class MyViewModel : ViewModel() {
var largeData: MyLargeObject? = null
}


🚩Хранить данные в `SharedPreferences` или `Room`

Если данные не нужны постоянно → используем SharedPreferences
getSharedPreferences("app_prefs", MODE_PRIVATE).edit()
.putString("last_data", jsonData)
.apply()


Если данные большие и важные → используем Room
@Dao
interface MyDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun saveData(data: MyData)
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
🤔 Что такое try(BufferReader) { … } catch { … }?

Это пример try-with-resources — конструкции, которая автоматически закрывает ресурс, реализующий интерфейс AutoCloseable. Здесь BufferedReader закрывается автоматически по завершении блока, даже если возникло исключение. Это упрощает управление ресурсами и снижает риск утечек.


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

При наследовании data class от какого-либо суперкласса в Kotlin, важно понимать, как работают свойства (поля) суперкласса и как они влияют на функциональность и структуру data class.

🚩Что происходит с полями суперкласса

🟠Наследование свойств
Поля (свойства), объявленные в суперклассе, автоматически становятся доступными в классе-наследнике. Вы можете использовать их в наследуемом классе как обычно. Однако свойства суперкласса не участвуют в автоматически сгенерированных функциях equals(), hashCode(), и toString() для data class.

🟠Автоматически сгенерированные функции в data-классе
У data class Kotlin генерирует функции equals(), hashCode(), toString(), copy() и другие. Эти функции работают только с параметрами, объявленными в первичном конструкторе data-класса. Поля, которые находятся в суперклассе, не участвуют в этих функциях.

🟠Почему поля суперкласса игнорируются
Это связано с тем, что контракт data class предполагает, что все его ключевые данные (data) определяются только параметрами первичного конструктора. Это позволяет гарантировать, что две одинаковые сущности будут сравниваться и обрабатываться корректно, основываясь только на данных самого data class.

// Суперкласс с полем name
open class Person(val name: String)

// Наследуемый data-класс
data class Employee(val id: Int, val position: String) : Person(name = "Default")


val employee1 = Employee(1, "Developer")
val employee2 = Employee(1, "Developer")

println(employee1 == employee2) // true, так как сравнение основано только на id и position
println(employee1.toString()) // Employee(id=1, position=Developer)


🟠Если нужно включить поля суперкласса в сравнение
Если вы хотите, чтобы поля суперкласса учитывались в логике equals() или hashCode(), вам нужно переопределить эти функции вручную.
data class Employee(val id: Int, val position: String) : Person(name = "Default") {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Employee || !super.equals(other)) return false
return id == other.id && position == other.position && name == other.name
}

override fun hashCode(): Int {
return 31 * super.hashCode() + id.hashCode() + position.hashCode()
}
}


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

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


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

Чтобы добавить кастомные атрибуты в Custom View, нужно:
Создать attrs.xml и описать атрибуты.
Добавить их в styleable и получить в Custom View.
Использовать атрибуты в XML или Kotlin.

🟠Создаём `attrs.xml`
Создаём файл res/values/attrs.xml, если его нет:
<resources>
<declare-styleable name="CustomButton">
<attr name="customText" format="string"/>
<attr name="customTextSize" format="dimension"/>
<attr name="customTextColor" format="color"/>
</declare-styleable>
</resources>


🟠Создаём `Custom View` и получаем атрибуты
Теперь создаём CustomButton.kt
class CustomButton @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : AppCompatButton(context, attrs, defStyleAttr) {

init {
context.theme.obtainStyledAttributes(attrs, R.styleable.CustomButton, 0, 0).apply {
try {
val text = getString(R.styleable.CustomButton_customText) ?: "Default"
val textSize = getDimension(R.styleable.CustomButton_customTextSize, 16f)
val textColor = getColor(R.styleable.CustomButton_customTextColor, Color.BLACK)

setText(text)
setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
setTextColor(textColor)
} finally {
recycle() // Освобождаем ресурсы
}
}
}
}


🟠Используем `Custom View` в XML
Теперь можно использовать CustomButton в activity_main.xml
<com.example.customviews.CustomButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:customText="Нажми меня"
app:customTextSize="20sp"
app:customTextColor="@android:color/holo_red_dark"/>


🟠Как изменить атрибуты в коде?
Можно обновлять свойства прямо в Kotlin
val button = findViewById<CustomButton>(R.id.customButton)
button.text = "Новый текст"
button.setTextSize(TypedValue.COMPLEX_UNIT_SP, 24f)
button.setTextColor(Color.BLUE)


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊2👍1
🤔 В чем отличие между job и supervisor job?

`Job` и `SupervisorJob` в корутинах Kotlin отличаются тем, как они обрабатывают исключения. `Job` прекращает выполнение всех дочерних корутин при возникновении исключения в одной из них. `SupervisorJob` позволяет другим дочерним корутинам продолжать выполнение независимо от исключений в соседних корутинах.

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

ViewModel и onSaveInstanceState служат для сохранения данных при изменении конфигурации активности или фрагмента (например, при повороте экрана). Однако они решают эту задачу по-разному и имеют разные области применения.

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

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

Когда система уничтожает и пересоздаёт Activity или Fragment, ViewModel остаётся в памяти до полного уничтожения владельца (например, выхода из Activity).
class MyViewModel : ViewModel() {
var counter: Int = 0 // Переменная, которая сохраняется при повороте экрана
}


Использование в Activity
class MainActivity : AppCompatActivity() {
private lateinit var viewModel: MyViewModel

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

viewModel = ViewModelProvider(this).get(MyViewModel::class.java)

// Теперь viewModel.counter сохранится при повороте экрана
}
}



🚩Плюсы

Хранит данные в памяти
до полного уничтожения Activity или Fragment.
Удобно для хранения сложных объектов
списки, модели, API-данные
Позволяет разделять логику и UI
улучшая архитектуру.

🚩Минусы

Данные исчезают при уничтожении Activity
например, при закрытии приложения
Не сохраняет данные при завершении процесса например, при нехватке памяти

🚩onSaveInstanceState()

Метод onSaveInstanceState() используется для сохранения данных в Bundle, который система автоматически передаёт при пересоздании Activity или Fragment.

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

Когда Activity уничтожается (например, при повороте экрана), система вызывает onSaveInstanceState(), в котором можно сохранить небольшие данные (строки, числа и т. д.). После пересоздания Activity эти данные можно восстановить из savedInstanceState.
class MainActivity : AppCompatActivity() {
private var counter: Int = 0 // Значение, которое мы хотим сохранить

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

// Восстанавливаем данные, если они есть
counter = savedInstanceState?.getInt("counter_key") ?: 0
}

override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putInt("counter_key", counter) // Сохраняем значение перед уничтожением Activity
}
}


🚩Плюсы

Сохраняет данные даже при завершении процесса (например, при нехватке памяти).
Позволяет быстро восстановить состояние UI (например, текст в EditText).

🚩Минусы

Подходит только для небольших данных (числа, строки).
Не подходит для хранения сложных объектов (списки, большие модели, API-данные).
Требует кодирования и декодирования данных в Bundle

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

В RxJava параллельность достигается через:
- Разные источники (Single, Observable) с subscribeOn разными пулами или общим
Schedulers.io().
- Затем их можно объединить с помощью операторов вроде zip, merge, combineLatest.
Всё это позволяет выполнять запросы одновременно, а затем собрать их результат в одну цепочку.


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

Для этого необходимо аннотировать класс Application аннотацией
@HiltAndroidApp, а компоненты, в которые требуется внедрение, — @AndroidEntryPoint. Затем зависимости определяются через модули и внедряются автоматически.

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

В interface можно определять свойства (val или var), но их реализация зависит от того, есть ли у них get и set.

🚩Свойства без реализации (только объявление)

В интерфейсе можно объявить val (только для чтения) или var (для чтения и записи), но без инициализации.
interface User {
val name: String // Объявляем свойство, но не реализуем
var age: Int // Может изменяться, но без начального значения
}


Использование в классе
class Person(override val name: String) : User {
override var age: Int = 25 // Обязательно реализовать
}


🚩Свойства с `get` (реализация в интерфейсе)

Можно задать кастомный геттер прямо в интерфейсе.
interface User {
val name: String
val greeting: String
get() = "Привет, $name!" // Реализация внутри интерфейса
}


Использование в классе
class Person(override val name: String) : User

fun main() {
val user = Person("Андрей")
println(user.greeting) // Привет, Андрей!
}


🚩Свойства с `get` и `set` (нельзя реализовать в интерфейсе)

Если в интерфейсе объявить var, то нельзя задать реализацию геттера и сеттера — их должен реализовать класс.
interface User {
var age: Int // Только объявление, без реализации
}


Использование в классе
class Person : User {
override var age: Int = 30 // Реализуем свойство
}


🚩Свойства с `get() = field` (не работает в интерфейсе!)

В interface нельзя использовать field (бэкинг-поле), потому что у интерфейсов нет состояния.
interface User {
var age: Int
get() = field // Ошибка! Нельзя использовать `field` в интерфейсе
set(value) { field = value }
}


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

Extension-функция выглядит как будто добавлена в класс, но на самом деле это статическая функция, которой не требуется менять сам класс. Она даёт синтаксический сахар, не добавляя нового в байткод класса.


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