Разница между var, val, const val
1. var — это изменяемая переменная. После инициализации мы можем изменять данные, хранящиеся в переменной.
Переменные val и const val доступны только для чтения — это неизменяемые переменные.
2. val — константа времени выполнения, т.е. значение можно назначить во время выполнения программы.
3. const val — константа времени компиляции, т.к. значения константам присваивается при компиляции (в момент, когда программа компилируется).
В отличие от val, значение const val должно быть известно во время компиляции.
Особенности const val:
• могут получать значение только базовых типов: Int, Double, Float, Long, Short, Byte, Char, String, Boolean.
• объявляются в глобальной области видимости, то есть за пределами функции main() или любой другой функции.
• нет пользовательского геттера.
1. var — это изменяемая переменная. После инициализации мы можем изменять данные, хранящиеся в переменной.
Переменные val и const val доступны только для чтения — это неизменяемые переменные.
2. val — константа времени выполнения, т.е. значение можно назначить во время выполнения программы.
3. const val — константа времени компиляции, т.к. значения константам присваивается при компиляции (в момент, когда программа компилируется).
В отличие от val, значение const val должно быть известно во время компиляции.
Особенности const val:
• могут получать значение только базовых типов: Int, Double, Float, Long, Short, Byte, Char, String, Boolean.
• объявляются в глобальной области видимости, то есть за пределами функции main() или любой другой функции.
• нет пользовательского геттера.
Как стоит объявлять свои константы в Kotlin — при помощи companion object или вне класса?
На самом деле оба эти подхода приемлемы. Однако, использование companion object может быть излишним: компилятор Kotlin преобразует companion object во вложенный класс. Слишком много кода для простой константы.
Если вам не требуется поведение, специфичное для companion object, объявляйте константы вне класса, так как это будет способствовать более эффективному байт-коду. Да и сам синтаксис объявления констант вне класса более чистый и читабельный.
На самом деле оба эти подхода приемлемы. Однако, использование companion object может быть излишним: компилятор Kotlin преобразует companion object во вложенный класс. Слишком много кода для простой константы.
Если вам не требуется поведение, специфичное для companion object, объявляйте константы вне класса, так как это будет способствовать более эффективному байт-коду. Да и сам синтаксис объявления констант вне класса более чистый и читабельный.
Как создать анимированные шейдеры в Jetpack Compose
Jetpack Compose — молодой, но бурно развивающийся фреймворк для разработки под Android, который обладает множеством не всегда очевидных фичей. Сегодня я хотел бы описать одну из таких встроенных возможностей: речь идет об использовании OpenGL-шейдеров. Они позволяют делать красивые анимированные интерфейсы.
Читать статью
Jetpack Compose — молодой, но бурно развивающийся фреймворк для разработки под Android, который обладает множеством не всегда очевидных фичей. Сегодня я хотел бы описать одну из таких встроенных возможностей: речь идет об использовании OpenGL-шейдеров. Они позволяют делать красивые анимированные интерфейсы.
Читать статью
Свойства, методы get и set
Свойства класса — это переменные, которые хранят состояние объекта класса. Как и любая переменная, свойство может иметь тип, имя и значение.
В классе можно объявить свойства с помощью ключевого слова var или val. Свойства, объявленные с var, могут быть изменены после их инициализации, а свойства, объявленные с val, только для чтения.
Если get и set методы не были созданы вручную, то для таких свойств Kotlin незаметно сам их генерирует. При этом для свойства, объявленного с val, генерируется get-метод, а для свойства, объявленного с var — и get, и set методы.
Свойства класса — это переменные, которые хранят состояние объекта класса. Как и любая переменная, свойство может иметь тип, имя и значение.
В классе можно объявить свойства с помощью ключевого слова var или val. Свойства, объявленные с var, могут быть изменены после их инициализации, а свойства, объявленные с val, только для чтения.
class Person {При создании своего класса мы хотим сами управлять его свойствами, контролируя то, какие данные могут быть предоставлены или перезаписаны. С этой целью создаются get и set методы (геттеры и сеттеры). Цель get-метода — вернуть значение, а set-метода — записать полученное значение в свойство класса.
var name: String = ""
val age: Int = 0
}
var name: String = ""В данном примере свойство name имеет тип String и начальное значение пустой строки. Геттер возвращает значение свойства, преобразованное к верхнему регистру. Сеттер устанавливает значение свойства с добавлением префикса "Name: " перед переданным значением. Слово field используется для обращения к текущему значению свойства.
get() = field.toUpperCase()
set(value) {
field = "Name: $value"
}
Если get и set методы не были созданы вручную, то для таких свойств Kotlin незаметно сам их генерирует. При этом для свойства, объявленного с val, генерируется get-метод, а для свойства, объявленного с var — и get, и set методы.
В чем отличие field от property?
В Kotlin свойство (property) — это абстракция над полями (fields), которая позволяет обращаться к значению переменной через методы геттера и сеттера, вместо прямого доступа к полю.
Field — это переменная, которая содержит значение и может быть доступна напрямую или через геттер/сеттер.
Пример определения свойства с геттером и сеттером в классе:
В Kotlin свойство (property) — это абстракция над полями (fields), которая позволяет обращаться к значению переменной через методы геттера и сеттера, вместо прямого доступа к полю.
Field — это переменная, которая содержит значение и может быть доступна напрямую или через геттер/сеттер.
Пример определения свойства с геттером и сеттером в классе:
class Person {В данном примере свойство name содержит поле, которое может быть доступно напрямую только внутри класса, и методы геттера и сеттера, которые позволяют получать и изменять значение свойства через специальные методы.
var name: String = ""
get() = field.toUpperCase() // возвращает значение поля name в верхнем регистре
set(value) {
field = value.trim() // устанавливает значение поля name без начальных и конечных пробелов
}
}
Что такое делегированные свойства (Delegated properties)?
Делегированные свойства (Delegated properties) — это свойства, которые не хранят своё значение напрямую, а делегируют это значение другому объекту, который реализует интерфейс Delegate. При доступе к свойству, его значение запрашивается у делегата, который может выполнить какую-то дополнительную логику, а затем вернуть требуемое значение. Пример:
Синтаксис выглядит так: val/var <имя свойства>: <Тип> by <выражение>. Выражение после by — делегат, потому что обращения get(), set() к свойству будут делегированы его методам getValue() и setValue(). Делегат не обязан реализовывать какой-то интерфейс, достаточно, чтобы у него были метод getValue() (и setValue() для var'ов) с определённой сигнатурой.
В Kotlin существуют несколько встроенных делегатов для работы с делегированными свойствами:
• lazy() — позволяет создавать лениво инициализированные свойства
• observable() — позволяет реагировать на изменения свойства
• vetoable() — позволяет отклонять изменения значения свойства на основе заданного условия
• notNull() — гарантирует, что свойство не будет иметь значение null
• map() — позволяет хранить значения свойств в словаре (Map)
Кроме того, в Kotlin можно создавать свои собственные делегаты, реализуя интерфейс ReadOnlyProperty или ReadWriteProperty. Это дает возможность создавать кастомные поведения для свойств, например, кеширование значений или логирование операций чтения/записи.
Делегированные свойства (Delegated properties) — это свойства, которые не хранят своё значение напрямую, а делегируют это значение другому объекту, который реализует интерфейс Delegate. При доступе к свойству, его значение запрашивается у делегата, который может выполнить какую-то дополнительную логику, а затем вернуть требуемое значение. Пример:
class Example {Ключевое слово by используется для обозначения свойств, методы чтения и записи которых реализованы другим объектом, который называют делегатом.
var p: String by Delegate()
}
Синтаксис выглядит так: val/var <имя свойства>: <Тип> by <выражение>. Выражение после by — делегат, потому что обращения get(), set() к свойству будут делегированы его методам getValue() и setValue(). Делегат не обязан реализовывать какой-то интерфейс, достаточно, чтобы у него были метод getValue() (и setValue() для var'ов) с определённой сигнатурой.
В Kotlin существуют несколько встроенных делегатов для работы с делегированными свойствами:
• lazy() — позволяет создавать лениво инициализированные свойства
• observable() — позволяет реагировать на изменения свойства
• vetoable() — позволяет отклонять изменения значения свойства на основе заданного условия
• notNull() — гарантирует, что свойство не будет иметь значение null
• map() — позволяет хранить значения свойств в словаре (Map)
Кроме того, в Kotlin можно создавать свои собственные делегаты, реализуя интерфейс ReadOnlyProperty или ReadWriteProperty. Это дает возможность создавать кастомные поведения для свойств, например, кеширование значений или логирование операций чтения/записи.
Блок инициализации (init блок)
Основной конструктор не может в себе содержать какую-либо логику по инициализации свойств (исполняемый код). Он предназначен исключительно для объявления свойств и присвоения им полученных значений. Поэтому вся логика может быть помещена в блок инициализации — блок кода, обязательно выполняемый при создании объекта независимо от того, с помощью какого конструктора этот объект создаётся. Помечается он словом init.
Основной конструктор не может в себе содержать какую-либо логику по инициализации свойств (исполняемый код). Он предназначен исключительно для объявления свойств и присвоения им полученных значений. Поэтому вся логика может быть помещена в блок инициализации — блок кода, обязательно выполняемый при создании объекта независимо от того, с помощью какого конструктора этот объект создаётся. Помечается он словом init.
class Person(val name: String, var age: Int) {По сути блок инициализации — это способ настроить переменные или значения, а также проверить, что были переданы допустимые параметры. Код в блоке инициализации выполняется сразу после создания экземпляра класса, т.е. сразу после вызова основного конструктора. В классе может быть один или несколько блоков инициализации и выполняться они будут последовательно.
var id: Int = 0
// require выдает ошибку с указанным текстом, если условие в левой части false
init {
require(name.isNotBlank(), { "У человека должно быть имя!" })
require(age > -1, { "Возраст не может быть отрицательным." })
}
constructor(name: String, age: Int, id: Int) : this(name, age) {
if (id > 0) this.id = id * 2
}
}
class Person(val name: String, var age: Int) {
// сначала вызывается основной конструктор и создаются свойства класса
// далее вызывается первый блок инициализации
init {
...
}
// после первого вызывается второй блок инициализации
init {Блок инициализации может быть добавлен, даже если у класса нет основного конструктора. В этом случае его код будет выполнен раньше кода вторичных конструкторов.
...
}
// и т.д.
}
Расскажите о Data классах. Какие преимущества они имеют?
Data класс предназначен исключительно для хранения каких-либо данных.
Основное преимущество: для параметров, переданных в основном конструкторе автоматически будут переопределены методы toString(), equals(), hashCode(), copy().
Также для каждой переменной, объявленной в основном конструкторе, автоматически генерируются функции componentN(), где N — номер позиции переменной в конструкторе.
Благодаря наличию вышеперечисленных функций внутри data класса мы исключаем написание шаблонного кода.
Data класс предназначен исключительно для хранения каких-либо данных.
Основное преимущество: для параметров, переданных в основном конструкторе автоматически будут переопределены методы toString(), equals(), hashCode(), copy().
Также для каждой переменной, объявленной в основном конструкторе, автоматически генерируются функции componentN(), где N — номер позиции переменной в конструкторе.
Благодаря наличию вышеперечисленных функций внутри data класса мы исключаем написание шаблонного кода.
Пару слов о полях и свойствах в Kotlin
Терминология свойств и полей в Kotlin может немного сбивать с толку, потому что технически в Kotlin нет полей. Вы не можете объявить поле. Все — свойства! Однако, во избежании путаницы, я предпочитаю разделять определения полей и свойств на следующей основе — полями являются приватные переменные-члены класса. Это то, для чего выделена память. Свойствами являются публичные или защищенные (protected) функциями геттеры и сеттеры, которые позволяют вам получить доступ к приватным полям.
Я считаю хорошей идеей разграничивать эти понятия таким образом, потому что это способствует моему пониманию, а также упрощает объяснение связанных с этим вещей.
Читать статью
Терминология свойств и полей в Kotlin может немного сбивать с толку, потому что технически в Kotlin нет полей. Вы не можете объявить поле. Все — свойства! Однако, во избежании путаницы, я предпочитаю разделять определения полей и свойств на следующей основе — полями являются приватные переменные-члены класса. Это то, для чего выделена память. Свойствами являются публичные или защищенные (protected) функциями геттеры и сеттеры, которые позволяют вам получить доступ к приватным полям.
Я считаю хорошей идеей разграничивать эти понятия таким образом, потому что это способствует моему пониманию, а также упрощает объяснение связанных с этим вещей.
Читать статью
Teletype
Пару слов о полях и свойствах в Kotlin
Терминология свойств и полей в Kotlin может немного сбивать с толку, потому что технически в Kotlin нет полей. Вы не можете объявить...
Что такое мульти-декларации (destructuring declarations)?
Мульти-декларации (destructuring declarations или деструктуризирующее присваивание) — это способ извлечения значений из объекта и присвоения их сразу нескольким переменным. В Kotlin этот механизм поддерживается с помощью оператора распаковки (destructuring operator) — componentN(), где N — номер компонента.
При создании data класса Kotlin автоматически создает функции componentN() для каждого свойства класса, где N — номер позиции переменной в конструкторе. Функции componentN() возвращают значения свойств в порядке их объявления в конструкторе. Это позволяет использовать мульти-декларации для распаковки значений свойств и присваивания их отдельным переменным.
Например, если у нас есть data класс Person с двумя свойствами name и age, мы можем использовать мульти-декларации, чтобы извлечь эти свойства и присвоить их двум переменным:
Мульти-декларации (destructuring declarations или деструктуризирующее присваивание) — это способ извлечения значений из объекта и присвоения их сразу нескольким переменным. В Kotlin этот механизм поддерживается с помощью оператора распаковки (destructuring operator) — componentN(), где N — номер компонента.
При создании data класса Kotlin автоматически создает функции componentN() для каждого свойства класса, где N — номер позиции переменной в конструкторе. Функции componentN() возвращают значения свойств в порядке их объявления в конструкторе. Это позволяет использовать мульти-декларации для распаковки значений свойств и присваивания их отдельным переменным.
Например, если у нас есть data класс Person с двумя свойствами name и age, мы можем использовать мульти-декларации, чтобы извлечь эти свойства и присвоить их двум переменным:
data class Person(val name: String, val age: Int)Также можно использовать мульти-декларации в циклах, чтобы итерироваться по спискам объектов и распаковывать значения свойств:
val person = Person("Alice", 29)
val (name, age) = person
println(name) // Alice
println(age) // 29
val people = listOf(Person("Alice", 30), Person("Bob", 40))Мульти-декларации также могут быть использованы с массивами и другими коллекциями:
for ((name, age) in people) {
println("$name is $age years old")
}
// Alice is 30 years old
// Bob is 40 years old
val list = listOf("apple", "banana", "orange")
val (first, second, third) = list
println(first) // apple
println(second) // banana
println(third) // orange
Что делает функция componentN()?
Функция componentN() возвращает значение переменной и позволяет обращаться к свойствам объекта класса по их порядковому номеру. Генерируется автоматически только для data классов.
Также функцию componentN() можно создать самому для класса, который не является data классом.
Функция componentN() возвращает значение переменной и позволяет обращаться к свойствам объекта класса по их порядковому номеру. Генерируется автоматически только для data классов.
Также функцию componentN() можно создать самому для класса, который не является data классом.
class Person(val firstName: String, val lastName: String, val age: Int) {Теперь можно использовать мульти-декларации для класса Person:
operator fun component1() = firstName
operator fun component2() = lastName
operator fun component3() = age
}
val person = Person("John", "Doe", 30)В данном примере мы определили функции component1(), component2() и component3() как операторы с ключевым словом operator. Они возвращают значения свойств firstName, lastName и age соответственно. После этого мы можем использовать мульти-декларации для разбивки объекта Person на отдельные переменные.
val (firstName, lastName, age) = person
println("$firstName $lastName is $age years old.")
Какие требования должны быть соблюдены для создания data класса?
Класс должен иметь хотя бы одно свойство, объявленное в основном конструкторе.
Все параметры основного конструктора должны быть отмечены val или var (рекомендуется val).
Классы данных не могут быть abstract, open, sealed или inner.
Класс должен иметь хотя бы одно свойство, объявленное в основном конструкторе.
Все параметры основного конструктора должны быть отмечены val или var (рекомендуется val).
Классы данных не могут быть abstract, open, sealed или inner.
Kotlin вместо bash. Прокачиваем автоматизацию на сервере
Для решения задач автоматизации рутинных процессов для системных администраторов и DevOps чаще всего используются или bash-сценарии или python. Первое решение косвенно используется и в описании Dockerfile, поскольку сценарий исполняемых команд принципиально ничем не отличается от запуска скрипта в какой-либо shell, второй подход чаще ассоциируется с автоматизацией, связанных с взаимодействием с хранилищами данных. Но несправедливо было бы обойти стороной возможность создания исполняемых сценариев на языке Kotlin, которые могут стать полноценной заменой bash-сценариям.
В этой статье мы рассмотрим несколько примеров использования Kotlin Scripting (KTS) для автоматизации в распределенной системе, будем использовать долгоживущие скрипты с ожиданием заданий через RabbitMQ, а также поработаем с файловой системой, внешними сервисами, а также попробуем использовать KTS для сборки Docker-контейнеров.
Читать статью
Для решения задач автоматизации рутинных процессов для системных администраторов и DevOps чаще всего используются или bash-сценарии или python. Первое решение косвенно используется и в описании Dockerfile, поскольку сценарий исполняемых команд принципиально ничем не отличается от запуска скрипта в какой-либо shell, второй подход чаще ассоциируется с автоматизацией, связанных с взаимодействием с хранилищами данных. Но несправедливо было бы обойти стороной возможность создания исполняемых сценариев на языке Kotlin, которые могут стать полноценной заменой bash-сценариям.
В этой статье мы рассмотрим несколько примеров использования Kotlin Scripting (KTS) для автоматизации в распределенной системе, будем использовать долгоживущие скрипты с ожиданием заданий через RabbitMQ, а также поработаем с файловой системой, внешними сервисами, а также попробуем использовать KTS для сборки Docker-контейнеров.
Читать статью
Teletype
Kotlin вместо bash. Прокачиваем автоматизацию на сервере
Для решения задач автоматизации рутинных процессов для системных администраторов и DevOps (которые, кроме всего прочего, нередко...
Можно ли наследоваться от data класса?
От data класса нельзя наследоваться т.к. он является final классом, но он может наследоваться от других классов.
От data класса нельзя наследоваться т.к. он является final классом, но он может наследоваться от других классов.
Почему классы в Kotlin по умолчанию final?
Классы в Kotlin по умолчанию являются final для того, чтобы избежать случайного наследования и переопределения методов. Это сделано для повышения безопасности кода и уменьшения сложности программы, так как ограничение наследования помогает избежать ошибок, связанных с неожиданным изменением поведения унаследованных методов.
В Kotlin рекомендуется использовать композицию вместо наследования для повторного использования кода и расширения функциональности.
Классы в Kotlin по умолчанию являются final для того, чтобы избежать случайного наследования и переопределения методов. Это сделано для повышения безопасности кода и уменьшения сложности программы, так как ограничение наследования помогает избежать ошибок, связанных с неожиданным изменением поведения унаследованных методов.
В Kotlin рекомендуется использовать композицию вместо наследования для повторного использования кода и расширения функциональности.
Что нужно сделать, чтобы класс можно было наследовать? (open)
По умолчанию, классы в Kotlin объявляются как final, то есть их нельзя наследовать. Если мы всё же попытаемся наследоваться от такого класса, то получим ошибку: “This type is final, so it cannot be inherited from”.
Чтобы класс можно было наследовать, его нужно объявить с модификатором open.
По умолчанию, классы в Kotlin объявляются как final, то есть их нельзя наследовать. Если мы всё же попытаемся наследоваться от такого класса, то получим ошибку: “This type is final, so it cannot be inherited from”.
Чтобы класс можно было наследовать, его нужно объявить с модификатором open.
open class Fraction {Не только классы, но и функции в Kotlin по умолчанию имеют статус final. Поэтому те функции, которые находятся в родительском классе и которые вы хотите переопределить в дочерних классах, также должны быть отмечены open.
...
}
open class Fraction {Свойства класса также по умолчанию являются final. Для возможности переопределения таких свойств в дочерних классах, не забудьте и их отметить ключевым словом open.
open fun toAttack() {
...
}
}
open class Fraction {При этом, если в открытом классе будут присутствовать функции и свойства, которые не отмечены словом open, то переопределяться они не будут. Но дочерний класс сможет к ним обращаться.
open val name: String = "default"
open fun toAttack() {
...
}
}
open class Fraction {
open val name: String = "default"
fun toAttack() {
...
}
}
class Horde : Fraction() {
override val name = "Horde"
}
class SomeClass() {
val horde = Horde()
horde.toAttack()
}
Как можно получить тип класса?
1. Получение типа класса через функцию ::class
Функция ::class возвращает объект KClass, который содержит информацию о типе класса во время выполнения.
Функция javaClass возвращает объект Class, который содержит информацию о типе класса во время выполнения.
Вызов функции ::class.java на объекте типа KClass возвращает объект Class, который содержит информацию о типе класса во время выполнения.
1. Получение типа класса через функцию ::class
Функция ::class возвращает объект KClass, который содержит информацию о типе класса во время выполнения.
class Person(val name: String, val age: Int)2. Получение типа класса через функцию javaClass
fun main() {
val person = Person("John", 30)
println(person::class) // выводит "class Person"
}
Функция javaClass возвращает объект Class, который содержит информацию о типе класса во время выполнения.
class Person(val name: String, val age: Int)3. Получение типа класса через функцию ::class.java
fun main() {
val person = Person("John", 30)
println(person.javaClass) // выводит "class Person"
}
Вызов функции ::class.java на объекте типа KClass возвращает объект Class, который содержит информацию о типе класса во время выполнения.
class Person(val name: String, val age: Int)
fun main() {
val person = Person("John", 30)
println(person::class.java) // выводит "class Person"
}
Осознанная оптимизация Compose
Compose — относительно молодая технология написания декларативного UI. Множество разработчиков даже не предполагают, что пишут неоптимальный код в такой критически важной части, и впоследствии это приводит к неожиданной низкой производительности и проседании метрик.
Наша команда Ozon Seller также столкнулась с этой проблемой. Мы решили собрать воедино все советы и наработки по написанию оптимизированного Compose-кода. Активное применение этих советов при оптимизации существующих экранов и написании новых существенно улучшило наши метрики: длительность лага по отношению к длительности скролла (hitch rate; чем меньше, тем лучше) экранов со списками упала в среднем с 15-19 % до 5-7 % (на 90-м перцентиле). Все эти советы и наработки мы описали в этой статье. Она будет полезна и начинающим, и опытным разработчикам, в ней подробно описаны оптимизации и механизмы Compose, а также рассказано про слабо задокументированных особенности и исправления ошибок, которые есть в других статьях. Давайте же начнём.
Читать статью
Compose — относительно молодая технология написания декларативного UI. Множество разработчиков даже не предполагают, что пишут неоптимальный код в такой критически важной части, и впоследствии это приводит к неожиданной низкой производительности и проседании метрик.
Наша команда Ozon Seller также столкнулась с этой проблемой. Мы решили собрать воедино все советы и наработки по написанию оптимизированного Compose-кода. Активное применение этих советов при оптимизации существующих экранов и написании новых существенно улучшило наши метрики: длительность лага по отношению к длительности скролла (hitch rate; чем меньше, тем лучше) экранов со списками упала в среднем с 15-19 % до 5-7 % (на 90-м перцентиле). Все эти советы и наработки мы описали в этой статье. Она будет полезна и начинающим, и опытным разработчикам, в ней подробно описаны оптимизации и механизмы Compose, а также рассказано про слабо задокументированных особенности и исправления ошибок, которые есть в других статьях. Давайте же начнём.
Читать статью
Teletype
Осознанная оптимизация Compose
Compose — относительно молодая технология написания декларативного UI. Множество разработчиков даже не предполагают, что пишут...
Что такое sealed класс (изолированный)?
Sealed class (изолированный класс) — это класс, который является абстрактным и используется в Kotlin для ограничения классов, которые могут наследоваться от него.
Основная идея заключается в том, что sealed class позволяет определить ограниченный и известный заранее набор подклассов, которые могут быть использованы.
Конструктор изолированного класса всегда приватен, и это нельзя изменить.
У sealed класса могут быть наследники, но все они должны находиться в одном пакете с изолированным классом. Изолированный класс "открыт" для наследования по умолчанию, указывать слово open не требуется.
Наследники sealed класса могут быть классами любого типа: data class, объектом, обычным классом, другим sealed классом. Классы, которые расширяют наследников sealed класса могут находиться где угодно.
Изолированные классы абстрактны и могут содержать в себе абстрактные компоненты.
Изолированные классы нельзя инициализировать.
При использовании when, все подклассы, которые не были проверены в конструкции, будут подсвечены IDE.
Не объявляется с ключевым словом inner.
Пример sealed класса:
В функции calculateArea мы используем выражение when, чтобы определить тип фигуры и вернуть ее площадь. Таким образом, если мы передадим Shape.Circle в calculateArea, то будет вычислена площадь круга.
В функции main мы создали объекты Circle, Rectangle и Triangle и передали их в calculateArea, чтобы вычислить их площади.
Sealed class (изолированный класс) — это класс, который является абстрактным и используется в Kotlin для ограничения классов, которые могут наследоваться от него.
Основная идея заключается в том, что sealed class позволяет определить ограниченный и известный заранее набор подклассов, которые могут быть использованы.
Конструктор изолированного класса всегда приватен, и это нельзя изменить.
У sealed класса могут быть наследники, но все они должны находиться в одном пакете с изолированным классом. Изолированный класс "открыт" для наследования по умолчанию, указывать слово open не требуется.
Наследники sealed класса могут быть классами любого типа: data class, объектом, обычным классом, другим sealed классом. Классы, которые расширяют наследников sealed класса могут находиться где угодно.
Изолированные классы абстрактны и могут содержать в себе абстрактные компоненты.
Изолированные классы нельзя инициализировать.
При использовании when, все подклассы, которые не были проверены в конструкции, будут подсвечены IDE.
Не объявляется с ключевым словом inner.
Пример sealed класса:
sealed class Shape {В этом примере мы определили sealed class Shape, который содержит три класса: Circle, Rectangle и Triangle. Эти классы наследуются от Shape. Это означает, что мы можем создавать объекты этих классов и использовать их, как объекты типа Shape.
class Circle(val radius: Double) : Shape()
class Rectangle(val width: Double, val height: Double) : Shape()
class Triangle(val base: Double, val height: Double) : Shape()
}
fun calculateArea(shape: Shape): Double {
return when (shape) {
is Shape.Circle -> Math.PI * shape.radius * shape.radius
is Shape.Rectangle -> shape.width * shape.height
is Shape.Triangle -> 0.5 * shape.base * shape.height
}
}
fun main() {
val circle = Shape.Circle(5.0)
val rectangle = Shape.Rectangle(2.0, 3.0)
val triangle = Shape.Triangle(4.0, 5.0)
println(calculateArea(circle)) // Output: 78.53981633974483
println(calculateArea(rectangle)) // Output: 6.0
println(calculateArea(triangle)) // Output: 10.0
}
В функции calculateArea мы используем выражение when, чтобы определить тип фигуры и вернуть ее площадь. Таким образом, если мы передадим Shape.Circle в calculateArea, то будет вычислена площадь круга.
В функции main мы создали объекты Circle, Rectangle и Triangle и передали их в calculateArea, чтобы вычислить их площади.
Какая разница между sealed class и enum?
Sealed class и Enum это два разных концепта в Kotlin, хотя их часто используют для ограничения набора возможных значений. Основная разница между ними:
• enum представляет собой конечный список значений, которые объявляются заранее в момент компиляции, и не могут быть расширены или изменены во время выполнения программы
• sealed class позволяет определять ограниченный набор значений, но эти значения могут быть расширены в будущем
В общем, enum class используется для представления конечного списка опций или состояний, тогда как sealed class используется для определения ограниченного набора значений, которые могут быть произвольными объектами.
Sealed class и Enum это два разных концепта в Kotlin, хотя их часто используют для ограничения набора возможных значений. Основная разница между ними:
• enum представляет собой конечный список значений, которые объявляются заранее в момент компиляции, и не могут быть расширены или изменены во время выполнения программы
• sealed class позволяет определять ограниченный набор значений, но эти значения могут быть расширены в будущем
В общем, enum class используется для представления конечного списка опций или состояний, тогда как sealed class используется для определения ограниченного набора значений, которые могут быть произвольными объектами.