Компаньон-объекты и статические данные
В Java для создания статических переменных и функций используется модификатор static. В Kotlin используется схожий механизм — компаньон-объект. Переменные и функции, объявленные внутри компаньон-объекта, становятся статическими.
Рассмотрим пример: создадим класс Sam с переменной count, изначально равной 0. В блоке init будем увеличивать count на единицу при создании каждого объекта и выводить сообщение о количестве созданных объектов.
class Sam {
var count = 0
init {
count++
println("Создано объектов: $count")
}
}
fun main() {
val test1 = Sam()
val test2 = Sam()
val test3 = Sam()
val test4 = Sam()
}
При запуске кода выводится четыре сообщения «Создано объектов: 1». Переменная count не является общей для всех объектов, а создается для каждого объекта отдельно.
Чтобы сделать count общей для всех объектов класса, необходимо объявить её внутри компаньон-объекта:
class Sam {
companion object {
var count = 0
}
init {
count++
println("Создано объектов: $count")
}
}
fun main() {
val test1 = Sam()
val test2 = Sam()
val test3 = Sam()
val test4 = Sam()
}
Теперь при запуске выводится «Создано объектов: 1», «Создано объектов: 2», «Создано объектов: 3», «Создано объектов: 4». Переменная count теперь принадлежит классу, а не каждому объекту. К ней можно обращаться через имя класса: Sam.count.
Изолированные классы
Изолированные классы похожи на перечисления, но каждый элемент представляет собой класс данных с множеством параметров и функций.
Создадим изолированный класс Db с различными типами баз данных:
sealed class Db(val id: Int, val con: String)
data class MongoDb(id: Int, con: String): Db(id, con)
data class MySql(id: Int, con: String): Db(id, con)
data class PostgreSql(id: Int, con: String, val isTest: Boolean): Db(id, con)
object Hulk : Db(1, "HulkConnection")
Теперь можно создавать объекты, выбирая нужный тип базы данных:
val db1 = MongoDb(5, "mongo")
val db2 = PostgreSql(10, "postgres", true)
Объекты, созданные на основе классов данных, имеют дополнительные возможности, например, функцию copy() для создания точной копии объекта и оператор == для сравнения объектов:
val dbCopy = db1.copy()
println(db1 == dbCopy) // Выведет true
val dbCopyModified = db1.copy(con = "modified")
println(db1 == dbCopyModified) // Выведет false
Функции можно добавлять как внутри классов данных, так и вне их, указывая принадлежность к конкретному классу:
fun MongoDb.printInfo() {
println("MongoDb id: $id, connection: $con")
}
val db3 = MongoDb(2, "anotherMongo")
if (db3 is MongoDb) db3.printInfo()
Функции высшего порядка
Рассмотрим создание функции, которая принимает другую функцию в качестве параметра. Создадим функцию filterList, которая принимает список строк и функцию-фильтр, возвращающую true или false:
fun filterList(list: List<String>, filter: (String) -> Boolean) {
list.forEach { element ->
if (filter(element)) println(element)
}
}
val filter = { element: String -> element.startsWith("J") }
filterList(listOf("Java", "Kotlin", "JavaScript"), filter)
Функцию-фильтр можно передавать как отдельный параметр или хранить в переменной:
val filter2 = { element: String -> element.startsWith("K") }
filterList(listOf("Java", "Kotlin", "JavaScript"), filter2)
Функция filterList демонстрирует работу с функциями высшего порядка в Kotlin.
В этом уроке мы рассмотрели компаньон-объекты для создания статических членов класса, изолированные классы для создания расширяемых перечислений и функции высшего порядка, позволяющие передавать функции в качестве параметров другим функциям. Эти инструменты повышают гибкость и выразительность кода на Kotlin.